# HG changeset patch # User Elliott Baron # Date 1357591718 18000 # Node ID 9e6bcfc40ea10c781dd101e96a4e6c2fc6eae777 # Parent 4c8a876b9dc0e633b3e13e89e5d21aedbd314fcb Create VM CPU agent and common bundles This commit extracts VM CPU data collection from SystemBackend into a vm-cpu-agent bundle. It also moves the VmCpuStatDAO from common-core into a vm-cpu-common bundle that registers the DAO once Storage is available. This also removes the DAO from DAOFactory. One side-effect is changing the visibility of VmLatestPojoListGetter to public in order for this DAO implementation (and DAOs in the other commits in this series) to access it. This also temporarily adds the vm-cpu-common bundle as a dependency to client-cli until my later dynamic vm-stat patch. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/004996.html diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 client/cli/pom.xml --- a/client/cli/pom.xml Mon Jan 07 15:46:47 2013 -0500 +++ b/client/cli/pom.xml Mon Jan 07 15:48:38 2013 -0500 @@ -100,6 +100,12 @@ org.osgi org.osgi.core + + + com.redhat.thermostat + thermostat-vm-cpu-common + ${project.version} + @@ -119,6 +125,8 @@ <_nouses>true + + *,com.redhat.thermostat.vm.cpu.common;resolution:=optional diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java --- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java Mon Jan 07 15:46:47 2013 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java Mon Jan 07 15:48:38 2013 -0500 @@ -48,12 +48,12 @@ import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.cli.HostVMArguments; import com.redhat.thermostat.common.cli.SimpleCommand; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmMemoryStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.common.utils.OSGIUtils; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class VMStatCommand extends SimpleCommand { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java --- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java Mon Jan 07 15:46:47 2013 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java Mon Jan 07 15:48:38 2013 -0500 @@ -48,7 +48,6 @@ import com.redhat.thermostat.common.Size; import com.redhat.thermostat.common.cli.TableRenderer; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmMemoryStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.locale.Translate; @@ -57,6 +56,7 @@ import com.redhat.thermostat.storage.model.TimeStampedPojoCorrelator; import com.redhat.thermostat.storage.model.VmCpuStat; import com.redhat.thermostat.storage.model.VmMemoryStat; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; class VMStatPrinter { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java --- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java Mon Jan 07 15:46:47 2013 -0500 +++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -64,7 +64,6 @@ import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.cli.SimpleArguments; import com.redhat.thermostat.common.dao.HostRef; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmMemoryStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.utils.OSGIUtils; @@ -74,6 +73,7 @@ import com.redhat.thermostat.storage.model.VmMemoryStat.Space; import com.redhat.thermostat.test.TestCommandContextFactory; import com.redhat.thermostat.test.TestTimerFactory; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class VmStatCommandTest { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java --- a/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java Mon Jan 07 15:46:47 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java Mon Jan 07 15:48:38 2013 -0500 @@ -56,8 +56,6 @@ public VmInfoDAO getVmInfoDAO(); - public VmCpuStatDAO getVmCpuStatDAO(); - public VmMemoryStatDAO getVmMemoryStatDAO(); public VmClassStatDAO getVmClassStatsDAO(); diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactoryImpl.java --- a/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactoryImpl.java Mon Jan 07 15:46:47 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactoryImpl.java Mon Jan 07 15:48:38 2013 -0500 @@ -59,7 +59,6 @@ private HostInfoDAO hostInfoDAO; private NetworkInterfaceInfoDAO networkInfoDAO; private VmInfoDAO vmInfoDAO; - private VmCpuStatDAO vmCpuStatDAO; private VmClassStatDAO vmClassStatDAO; private VmMemoryStatDAO vmMemStatDAO; private VmGcStatDAO vmGcStatDAO; @@ -109,12 +108,6 @@ } @Override - public VmCpuStatDAO getVmCpuStatDAO() { - ensureStorageConnected(); - return vmCpuStatDAO; - } - - @Override public VmMemoryStatDAO getVmMemoryStatDAO() { ensureStorageConnected(); return vmMemStatDAO; @@ -157,7 +150,6 @@ registerAndRecordService(VmInfoDAO.class, getVmInfoDAO()); registerAndRecordService(VmClassStatDAO.class, getVmClassStatsDAO()); - registerAndRecordService(VmCpuStatDAO.class, getVmCpuStatDAO()); registerAndRecordService(VmGcStatDAO.class, getVmGcStatDAO()); registerAndRecordService(VmMemoryStatDAO.class, getVmMemoryStatDAO()); } @@ -171,7 +163,6 @@ hostInfoDAO = new HostInfoDAOImpl(storage, agentDAO); networkInfoDAO = new NetworkInterfaceInfoDAOImpl(storage); vmInfoDAO = new VmInfoDAOImpl(storage); - vmCpuStatDAO = new VmCpuStatDAOImpl(storage); vmClassStatDAO = new VmClassStatDAOImpl(storage); vmMemStatDAO = new VmMemoryStatDAOImpl(storage); vmGcStatDAO = new VmGcStatDAOImpl(storage); diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java --- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.common.dao; - -import java.util.List; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.model.VmCpuStat; - -public interface VmCpuStatDAO { - - static final Key vmCpuLoadKey = new Key<>("cpuLoad", false); - - static final Category vmCpuStatCategory = new Category("vm-cpu-stats", - Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, vmCpuLoadKey); - - public abstract List getLatestVmCpuStats(VmRef ref, long since); - - public abstract void putVmCpuStat(VmCpuStat stat); - -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java --- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.common.dao; - -import java.util.List; - -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.model.VmCpuStat; - -class VmCpuStatDAOImpl implements VmCpuStatDAO { - - private final Storage storage; - private final VmLatestPojoListGetter getter; - - VmCpuStatDAOImpl(Storage storage) { - this.storage = storage; - storage.registerCategory(vmCpuStatCategory); - this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory, VmCpuStat.class); - } - - @Override - public List getLatestVmCpuStats(VmRef ref, long since) { - return getter.getLatest(ref, since); - } - - @Override - public void putVmCpuStat(VmCpuStat stat) { - storage.putPojo(vmCpuStatCategory, false, stat); - } -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java --- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java Mon Jan 07 15:46:47 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java Mon Jan 07 15:48:38 2013 -0500 @@ -47,13 +47,13 @@ import com.redhat.thermostat.storage.core.Query.Criteria; import com.redhat.thermostat.storage.model.TimeStampedPojo; -class VmLatestPojoListGetter { +public class VmLatestPojoListGetter { private final Storage storage; private final Category cat; private final Class resultClass; - VmLatestPojoListGetter(Storage storage, Category cat, Class resultClass) { + public VmLatestPojoListGetter(Storage storage, Category cat, Class resultClass) { this.storage = storage; this.cat = cat; this.resultClass = resultClass; diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java --- a/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java Mon Jan 07 15:46:47 2013 -0500 +++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -131,8 +131,8 @@ daoFactory.registerDAOsAndStorageAsOSGiServices(); - // currently 10 DAOs and Storage are registered - assertEquals(10, bundleContext.getAllServices().size()); + // currently 9 DAOs and Storage are registered + assertEquals(9, bundleContext.getAllServices().size()); } @Test diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java --- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.common.dao; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collection; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.Query.Criteria; -import com.redhat.thermostat.storage.model.VmCpuStat; -import com.redhat.thermostat.test.MockQuery; - -public class VmCpuStatDAOTest { - - private static final Long TIMESTAMP = 1234L; - private static final Integer VM_ID = 321; - private static final Double CPU_LOAD = 9.9; - - private VmCpuStat cpuStat; - - @Before - public void setUp() { - cpuStat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD); - } - - @Test - public void testCategory() { - assertEquals("vm-cpu-stats", VmCpuStatDAO.vmCpuStatCategory.getName()); - Collection> keys = VmCpuStatDAO.vmCpuStatCategory.getKeys(); - assertTrue(keys.contains(new Key<>("agentId", true))); - assertTrue(keys.contains(new Key("timeStamp", false))); - assertTrue(keys.contains(new Key("vmId", true))); - assertTrue(keys.contains(new Key("cpuLoad", false))); - assertEquals(4, keys.size()); - } - - @Test - public void testGetLatestCpuStatsBasic() { - - @SuppressWarnings("unchecked") - Cursor cursor = mock(Cursor.class); - when(cursor.hasNext()).thenReturn(true).thenReturn(false); - when(cursor.next()).thenReturn(cpuStat); - - Storage storage = mock(Storage.class); - when(storage.createQuery()).then(new Answer() { - @Override - public Query answer(InvocationOnMock invocation) throws Throwable { - return new MockQuery(); - } - }); - when(storage.findAllPojos(any(Query.class), same(VmCpuStat.class))).thenReturn(cursor); - - HostRef hostRef = mock(HostRef.class); - when(hostRef.getAgentId()).thenReturn("system"); - - VmRef vmRef = mock(VmRef.class); - when(vmRef.getAgent()).thenReturn(hostRef); - when(vmRef.getId()).thenReturn(VM_ID); - - - VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage); - List vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE); - - ArgumentCaptor arg = ArgumentCaptor.forClass(MockQuery.class); - verify(storage).findAllPojos(arg.capture(), same(VmCpuStat.class)); - assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); - - assertEquals(1, vmCpuStats.size()); - VmCpuStat stat = vmCpuStats.get(0); - assertEquals(TIMESTAMP, (Long) stat.getTimeStamp()); - assertEquals(CPU_LOAD, stat.getCpuLoad(), 0.001); - assertEquals(VM_ID, (Integer) stat.getVmId()); - } - - @Test - public void testPutVmCpuStat() { - Storage storage = mock(Storage.class); - VmCpuStat stat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD); - VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage); - dao.putVmCpuStat(stat); - - verify(storage).putPojo(VmCpuStatDAO.vmCpuStatCategory, false, stat); - - } -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 distribution/config/commands/agent.properties --- a/distribution/config/commands/agent.properties Mon Jan 07 15:46:47 2013 -0500 +++ b/distribution/config/commands/agent.properties Mon Jan 07 15:48:38 2013 -0500 @@ -13,6 +13,8 @@ thermostat-host-cpu-agent-@project.version@.jar, \ thermostat-host-memory-common-@project.version@.jar, \ thermostat-host-memory-agent-@project.version@.jar, \ + thermostat-vm-cpu-common-@project.version@.jar, \ + thermostat-vm-cpu-agent-@project.version@.jar, \ thermostat-vm-heap-analysis-common-@project.version@.jar, \ thermostat-vm-heap-analysis-agent-@project.version@.jar, \ thermostat-killvm-agent-@project.version@.jar, \ diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 distribution/config/commands/gui.properties --- a/distribution/config/commands/gui.properties Mon Jan 07 15:46:47 2013 -0500 +++ b/distribution/config/commands/gui.properties Mon Jan 07 15:48:38 2013 -0500 @@ -22,6 +22,7 @@ thermostat-host-memory-client-swing-@project.version@.jar, \ thermostat-vm-overview-client-core-@project.version@.jar, \ thermostat-vm-overview-client-swing-@project.version@.jar, \ + thermostat-vm-cpu-common-@project.version@.jar, \ thermostat-vm-cpu-client-core-@project.version@.jar, \ thermostat-vm-cpu-client-swing-@project.version@.jar, \ thermostat-vm-gc-client-core-@project.version@.jar, \ diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 distribution/config/commands/vm-stat.properties --- a/distribution/config/commands/vm-stat.properties Mon Jan 07 15:46:47 2013 -0500 +++ b/distribution/config/commands/vm-stat.properties Mon Jan 07 15:48:38 2013 -0500 @@ -1,4 +1,5 @@ bundles = thermostat-client-cli-${project.version}.jar, \ + thermostat-vm-cpu-common-${project.version}.jar, \ thermostat-storage-mongodb-${project.version}.jar, \ thermostat-web-common-${project.version}.jar, \ thermostat-web-client-${project.version}.jar, \ diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 distribution/pom.xml --- a/distribution/pom.xml Mon Jan 07 15:46:47 2013 -0500 +++ b/distribution/pom.xml Mon Jan 07 15:48:38 2013 -0500 @@ -412,6 +412,11 @@ com.redhat.thermostat + thermostat-vm-cpu-agent + ${project.version} + + + com.redhat.thermostat thermostat-vm-gc-client-core ${project.version} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 eclipse/com.redhat.thermostat.client.feature/feature.xml --- a/eclipse/com.redhat.thermostat.client.feature/feature.xml Mon Jan 07 15:46:47 2013 -0500 +++ b/eclipse/com.redhat.thermostat.client.feature/feature.xml Mon Jan 07 15:48:38 2013 -0500 @@ -196,4 +196,11 @@ version="0.0.0" unpack="false"/> + + diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java --- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java Mon Jan 07 15:46:47 2013 -0500 +++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java Mon Jan 07 15:48:38 2013 -0500 @@ -37,7 +37,6 @@ package com.redhat.thermostat.backend.system; import java.net.URISyntaxException; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java --- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java Mon Jan 07 15:46:47 2013 -0500 +++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatVmListener.java Mon Jan 07 15:48:38 2013 -0500 @@ -36,8 +36,6 @@ package com.redhat.thermostat.backend.system; -import java.util.ArrayList; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/main/java/com/redhat/thermostat/backend/system/ProcessStatusInfo.java --- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/ProcessStatusInfo.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.backend.system; - -public class ProcessStatusInfo { - - /* All times are measured in clock ticks */ - - private final int pid; - private final long userTime; - private final long kernelTime; - - public ProcessStatusInfo(int pid, long userTime, long kernelTime) { - this.pid = pid; - this.userTime = userTime; - this.kernelTime = kernelTime; - } - - public int getPid() { - return pid; - } - - /** - * @return the time this process has spent in user-mode as a number of - * kernel ticks - */ - public long getUserTime() { - return userTime; - } - - /** - * @return the time this process spent in kernel-mode as a number of kernel - * ticks - */ - public long getKernelTime() { - return kernelTime; - } - -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/main/java/com/redhat/thermostat/backend/system/ProcessStatusInfoBuilder.java --- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/ProcessStatusInfoBuilder.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.backend.system; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.util.Scanner; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.utils.ProcDataSource; - -/** - * Extract status information about the process from /proc/. This is what tools - * like {@code ps} and {@code top} use. - * - * @see {@code proc(5)} - */ -public class ProcessStatusInfoBuilder { - - private static final Logger logger = LoggingUtils.getLogger(ProcessStatusInfoBuilder.class); - - private final ProcDataSource dataSource; - - public ProcessStatusInfoBuilder(ProcDataSource dataSource) { - this.dataSource = dataSource; - } - - public ProcessStatusInfo build(int pid) { - try (BufferedReader reader = new BufferedReader(dataSource.getStatReader(pid))) { - return build(reader); - } catch (IOException e) { - logger.log(Level.WARNING, "unable to read stat info for " + pid); - } - - return null; - } - - private ProcessStatusInfo build(Reader r) throws IOException { - - int pid = -1; - long utime = -1; - long stime = -1; - - Scanner scanner = null; - - /* TODO map these (effectively c) data types to java types more sanely */ - - try (BufferedReader reader = new BufferedReader(r)) { - String statusLine = reader.readLine(); - - /* be prepared for process names like '1 ) 2 3 4 foo 5' */ - - scanner = new Scanner(statusLine); - pid = scanner.nextInt(); - scanner.close(); - - int execEndNamePos = statusLine.lastIndexOf(')'); - - String cleanStatusLine = statusLine.substring(execEndNamePos + 1); - - scanner = new Scanner(cleanStatusLine); - /* state = */scanner.next(); - /* ppid = */scanner.nextInt(); - /* pgrp = */scanner.nextInt(); - /* session = */scanner.nextInt(); - /* tty_nr = */scanner.nextInt(); - /* tpgid = */scanner.nextInt(); - /* flags = */scanner.nextInt(); - /* minflt = */scanner.nextLong(); - /* cminflt = */scanner.nextLong(); - /* majflt = */scanner.nextLong(); - /* cmajflt = */scanner.nextLong(); - utime = scanner.nextLong(); - stime = scanner.nextLong(); - scanner.close(); - } - - return new ProcessStatusInfo(pid, utime, stime); - - } - -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java --- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java Mon Jan 07 15:46:47 2013 -0500 +++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java Mon Jan 07 15:48:38 2013 -0500 @@ -53,23 +53,17 @@ import com.redhat.thermostat.backend.Backend; import com.redhat.thermostat.backend.BackendID; import com.redhat.thermostat.backend.BackendsProperties; -import com.redhat.thermostat.common.Clock; -import com.redhat.thermostat.common.SystemClock; import com.redhat.thermostat.common.dao.HostInfoDAO; import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.model.NetworkInterfaceInfo; -import com.redhat.thermostat.storage.model.VmCpuStat; import com.redhat.thermostat.utils.ProcDataSource; -import com.redhat.thermostat.utils.SysConf; public class SystemBackend extends Backend implements JvmStatusNotifier, JvmStatusListener { private static final Logger logger = LoggingUtils.getLogger(SystemBackend.class); private HostInfoDAO hostInfos; - private VmCpuStatDAO vmCpuStats; private NetworkInterfaceInfoDAO networkInterfaces; private final Set pidsToMonitor = new CopyOnWriteArraySet(); @@ -80,9 +74,8 @@ private HostIdentifier hostId = null; private MonitoredHost host = null; - private JvmStatHostListener hostListener; + private JvmStatHostListener hostListener = null; - private final VmCpuStatBuilder vmCpuBuilder; private final HostInfoBuilder hostInfoBuilder; public SystemBackend() { @@ -92,20 +85,13 @@ setConfigurationValue(BackendsProperties.DESCRIPTION.name(), "Gathers basic information from the system"); setConfigurationValue(BackendsProperties.VERSION.name(), "0.5.0"); - Clock clock = new SystemClock(); - ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(new ProcDataSource()); - long ticksPerSecond = SysConf.getClockTicksPerSecond(); ProcDataSource source = new ProcDataSource(); hostInfoBuilder = new HostInfoBuilder(source); - - int cpuCount = hostInfoBuilder.getCpuInfo().count; - vmCpuBuilder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, builder); } @Override protected void setDAOFactoryAction() { hostInfos = df.getHostInfoDAO(); - vmCpuStats = df.getVmCpuStatDAO(); networkInterfaces = df.getNetworkInterfaceInfoDAO(); hostListener = new JvmStatHostListener(df.getVmInfoDAO(), df.getVmMemoryStatDAO(), df.getVmGcStatDAO(), df.getVmClassStatsDAO(), getObserveNewJvm()); } @@ -133,17 +119,6 @@ for (NetworkInterfaceInfo info: NetworkInfoBuilder.build()) { networkInterfaces.putNetworkInterfaceInfo(info); } - - for (Integer pid : pidsToMonitor) { - if (vmCpuBuilder.knowsAbout(pid)) { - VmCpuStat dataBuilt = vmCpuBuilder.build(pid); - if (dataBuilt != null) { - vmCpuStats.putVmCpuStat(dataBuilt); - } - } else { - vmCpuBuilder.learnAbout(pid); - } - } } }, 0, procCheckInterval); @@ -221,7 +196,6 @@ @Override public void jvmStopped(int vmId) { pidsToMonitor.remove(vmId); - vmCpuBuilder.forgetAbout(vmId); } @Override diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/main/java/com/redhat/thermostat/backend/system/VmCpuStatBuilder.java --- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/VmCpuStatBuilder.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.backend.system; - -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.Clock; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.storage.model.VmCpuStat; - -public class VmCpuStatBuilder { - - private static final Logger logger = LoggingUtils.getLogger(VmCpuStatBuilder.class); - - // pid -> ticks - private final Map lastProcessTicks = new HashMap(); - // pid -> last time the ticks were updated - private final Map lastProcessTickTime = new HashMap(); - - private final Clock clock; - private final int cpuCount; - private final long ticksPerSecond; - private final ProcessStatusInfoBuilder statusBuilder; - - public VmCpuStatBuilder(Clock clock, int cpuCount, long ticksPerSecond, ProcessStatusInfoBuilder statusBuilder) { - this.clock = clock; - this.cpuCount = cpuCount; - this.ticksPerSecond = ticksPerSecond; - this.statusBuilder = statusBuilder; - } - - /** - * @param pid the process id - * @return an object representing the cpu usage of the process, or null if - * the information can not be found. - */ - public synchronized VmCpuStat build(Integer pid) { - if (!lastProcessTicks.containsKey(pid) || !lastProcessTickTime.containsKey(pid)) { - throw new IllegalArgumentException("unknown pid"); - } - - ProcessStatusInfo info = statusBuilder.build(pid); - if (info == null) { - return null; - } - long miliTime = clock.getRealTimeMillis(); - long time = clock.getMonotonicTimeNanos(); - long programTicks = (info.getKernelTime() + info.getUserTime()); - double cpuLoad = 0.0; - - double timeDelta = (time - lastProcessTickTime.get(pid)) * 1E-9; - long programTicksDelta = programTicks - lastProcessTicks.get(pid); - // 100 as in 100 percent. - cpuLoad = programTicksDelta * (100.0 / timeDelta / ticksPerSecond / cpuCount); - - if (cpuLoad < 0.0 || cpuLoad > 100.0) { - logger.log(Level.WARNING, "cpu load for " + pid + " is outside [0,100]: " + cpuLoad); - logger.log(Level.WARNING, " (" + pid + ") programTicks: " + programTicks); - logger.log(Level.WARNING, " (" + pid + ") programTicksDelta: " + programTicksDelta); - logger.log(Level.WARNING, " (" + pid + ") time: " + time); - logger.log(Level.WARNING, " (" + pid + ") timeDelta: " + timeDelta); - logger.log(Level.WARNING, " (" + pid + ") ticksPerSecond: " + ticksPerSecond); - logger.log(Level.WARNING, " (" + pid + ") cpuCount: " + cpuCount); - } - - lastProcessTicks.put(pid, programTicks); - lastProcessTickTime.put(pid, time); - - return new VmCpuStat(miliTime, pid, cpuLoad); - } - - public synchronized boolean knowsAbout(int pid) { - return (lastProcessTickTime.containsKey(pid) && lastProcessTicks.containsKey(pid)); - } - - public synchronized void learnAbout(int pid) { - long time = clock.getMonotonicTimeNanos(); - ProcessStatusInfo info = statusBuilder.build(pid); - if (info == null) { - logger.log(Level.WARNING, "can not learn about pid " + pid + " : statusBuilder returned null"); - return; - } - - lastProcessTickTime.put(pid, time); - lastProcessTicks.put(pid, info.getUserTime()+ info.getKernelTime()); - } - - public synchronized void forgetAbout(int pid) { - lastProcessTicks.remove(pid); - lastProcessTickTime.remove(pid); - } - -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/test/java/com/redhat/thermostat/backend/system/ProcessStatusInfoBuilderTest.java --- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/ProcessStatusInfoBuilderTest.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.backend.system; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.io.StringReader; - -import org.junit.Test; - -import com.redhat.thermostat.utils.ProcDataSource; - -public class ProcessStatusInfoBuilderTest { - - @Test - public void testSimpleProcessStatus() { - ProcDataSource dataSource = new ProcDataSource(); - ProcessStatusInfo stat = new ProcessStatusInfoBuilder(dataSource).build(1); - assertNotNull(stat); - } - - @Test - public void testKnownProcessStatus() throws IOException { - final int PID = 10363; - String PROCESS_NAME = "(bash)"; - String STATE = "S"; - String PPID = "1737"; - String PROCESS_GROUP_ID = "10363"; - String SESSION_ID = "10363"; - String TTY_NUMBER = "34817"; - String TTY_PROCESS_GROUP_ID = "11404"; - String FLAGS_WORD = "4202496"; - String MINOR_FAULTS = "8093"; - String MINOR_FAULTS_CHILDREN = "607263"; - String MAJOR_FAULTS = "1"; - String MAJOR_FAULTS_CHILDREN = "251"; - final long USER_TIME_TICKS = 21; - final long KERNEL_TIME_TICKS = 7; - final long USER_TIME_CHILDREN = 10; - String KERNEL_TIME_CHILDREN = "1000"; - String PRIORITY = "20"; - String statString = "" + - PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " " - + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " " - + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " " - + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " + - USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " + - KERNEL_TIME_CHILDREN + " " + PRIORITY; - - ProcDataSource dataSource = mock(ProcDataSource.class); - when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString)); - ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(dataSource); - ProcessStatusInfo stat = builder.build(PID); - - verify(dataSource).getStatReader(PID); - assertNotNull(stat); - assertEquals(PID, stat.getPid()); - assertEquals(USER_TIME_TICKS, stat.getUserTime()); - assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime()); - } - - @Test - public void testBadProcessName() throws IOException { - final int PID = 10363; - String PROCESS_NAME = "(secretly-bad process sleep 10 20 ) 6)"; - String STATE = "S"; - String PPID = "1737"; - String PROCESS_GROUP_ID = "10363"; - String SESSION_ID = "10363"; - String TTY_NUMBER = "34817"; - String TTY_PROCESS_GROUP_ID = "11404"; - String FLAGS_WORD = "4202496"; - String MINOR_FAULTS = "8093"; - String MINOR_FAULTS_CHILDREN = "607263"; - String MAJOR_FAULTS = "1"; - String MAJOR_FAULTS_CHILDREN = "251"; - final long USER_TIME_TICKS = 21; - final long KERNEL_TIME_TICKS = 7; - final long USER_TIME_CHILDREN = 10; - String KERNEL_TIME_CHILDREN = "1000"; - String PRIORITY = "20"; - String statString = "" + - PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " " - + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " " - + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " " - + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " + - USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " + - KERNEL_TIME_CHILDREN + " " + PRIORITY; - - ProcDataSource dataSource = mock(ProcDataSource.class); - when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString)); - ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(dataSource); - ProcessStatusInfo stat = builder.build(PID); - - verify(dataSource).getStatReader(PID); - assertNotNull(stat); - assertEquals(PID, stat.getPid()); - assertEquals(USER_TIME_TICKS, stat.getUserTime()); - assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime()); - } - -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java --- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java Mon Jan 07 15:46:47 2013 -0500 +++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -47,7 +47,6 @@ import com.redhat.thermostat.common.dao.DAOFactory; import com.redhat.thermostat.common.dao.HostInfoDAO; import com.redhat.thermostat.common.dao.NetworkInterfaceInfoDAO; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.storage.core.Storage; public class SystemBackendTest { @@ -58,12 +57,10 @@ public void setUp() { Storage s = mock(Storage.class); HostInfoDAO hDAO = mock(HostInfoDAO.class); - VmCpuStatDAO vDAO = mock(VmCpuStatDAO.class); NetworkInterfaceInfoDAO nDAO = mock(NetworkInterfaceInfoDAO.class); DAOFactory df = mock(DAOFactory.class); when(df.getStorage()).thenReturn(s); when(df.getHostInfoDAO()).thenReturn(hDAO); - when(df.getVmCpuStatDAO()).thenReturn(vDAO); when(df.getNetworkInterfaceInfoDAO()).thenReturn(nDAO); b = new SystemBackend(); b.setDAOFactory(df); diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 system-backend/src/test/java/com/redhat/thermostat/backend/system/VmCpuStatBuilderTest.java --- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/VmCpuStatBuilderTest.java Mon Jan 07 15:46:47 2013 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright 2012 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.backend.system; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.Test; - -import com.redhat.thermostat.common.Clock; -import com.redhat.thermostat.storage.model.VmCpuStat; -import com.redhat.thermostat.test.Bug; - -public class VmCpuStatBuilderTest { - - @Test - public void testBuilderKnowsNothing() { - Clock clock = mock(Clock.class); - ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); - int cpuCount = 0; - long ticksPerSecond = 0; - VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, statusBuilder); - - assertFalse(builder.knowsAbout(0)); - assertFalse(builder.knowsAbout(1)); - assertFalse(builder.knowsAbout(Integer.MIN_VALUE)); - assertFalse(builder.knowsAbout(Integer.MAX_VALUE)); - - } - - @Test(expected = IllegalArgumentException.class) - public void testBuilderThrowsOnBuildOfUnknownPid() { - Clock clock = mock(Clock.class); - int cpuCount = 0; - long ticksPerSecond = 0; - ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); - VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, statusBuilder); - builder.build(0); - } - - @Test - public void testBuildNullOnInsufficentInformation() { - int PID = 0; - int cpuCount = 0; - long ticksPerSecond = 0; - final long CLOCK1 = 10000; - final long CLOCK2 = 20000; - final ProcessStatusInfo initialInfo = new ProcessStatusInfo(PID, 1, 2); - final ProcessStatusInfo laterInfo = null; - - Clock clock = mock(Clock.class); - when(clock.getMonotonicTimeNanos()).thenReturn((long) (CLOCK1 * 1E6)).thenReturn((long) (CLOCK2 * 1E6)); - - ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); - when(statusBuilder.build(any(Integer.class))).thenReturn(initialInfo).thenReturn(laterInfo).thenReturn(null); - - VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, statusBuilder); - - builder.learnAbout(PID); - assertEquals(null, builder.build(PID)); - } - - @Test - public void testSaneBuild() { - final int PID = 0; - - final int CPU_COUNT = 3; - - final long USER_INITIAL_TICKS = 1; - final long KERNEL_INITIAL_TICKS = 1; - - final long USER_LATER_TICKS = 10; - final long KERNEL_LATER_TICKS = 10; - - final long CLOCK1 = 10000; - final long CLOCK2 = 20000; - - final long TICKS_PER_SECOND = 100; - - final double CPU_LOAD_PERCENT = - 100.0 - * ((USER_LATER_TICKS + KERNEL_LATER_TICKS) - (USER_INITIAL_TICKS + KERNEL_INITIAL_TICKS)) - / TICKS_PER_SECOND - / ((CLOCK2 - CLOCK1) * 1E-3 /* millis to seconds */) - / CPU_COUNT; - - final ProcessStatusInfo initialInfo = new ProcessStatusInfo(PID, USER_INITIAL_TICKS, KERNEL_INITIAL_TICKS); - final ProcessStatusInfo laterInfo = new ProcessStatusInfo(PID, USER_LATER_TICKS, KERNEL_LATER_TICKS); - - Clock clock = mock(Clock.class); - when(clock.getRealTimeMillis()).thenReturn(CLOCK2); - when(clock.getMonotonicTimeNanos()).thenReturn((long) (CLOCK1 * 1E6)).thenReturn((long) (CLOCK2 * 1E6)); - - ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); - when(statusBuilder.build(any(Integer.class))).thenReturn(initialInfo).thenReturn(laterInfo).thenReturn(null); - - VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, CPU_COUNT, TICKS_PER_SECOND, statusBuilder); - - builder.learnAbout(PID); - VmCpuStat stat = builder.build(PID); - - assertNotNull(stat); - assertEquals(PID, stat.getVmId()); - assertEquals(CLOCK2, stat.getTimeStamp()); - assertEquals(CPU_LOAD_PERCENT, stat.getCpuLoad(), 0.0001); - } - - @Bug(id="1051", - summary="Avoid exceptions when reading /proc/ for dead processes", - url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1051") - @Test - public void testNoExceptionForBuilderLearningAboutDeadProcess() { - Clock clock = mock(Clock.class); - when(clock.getMonotonicTimeNanos()).thenReturn((long) (10000 * 1E6)); - ProcessStatusInfoBuilder procBuilder = mock(ProcessStatusInfoBuilder.class); - // This thing returns null if the /proc entry goes away. Rather than try to - // 'guess' at a pid that will not be present during test, just mock this. - when(procBuilder.build(any(Integer.class))).thenReturn(null); - VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, 3, 100, procBuilder); - // If we can't handle a process' /proc entry disappearing, the next line - // will throw exception. If it does not, then we are okay. - try { - builder.learnAbout(0); - } catch (Exception e) { - // Shouldn't happen. - assertTrue(false); - } - } -} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/pom.xml Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,78 @@ + + + 4.0.0 + + thermostat-vm-cpu + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-vm-cpu-agent + bundle + Thermostat VM CPU Agent plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + Red Hat, Inc. + com.redhat.thermostat.vm.cpu.agent + com.redhat.thermostat.vm.cpu.agent.internal.Activator + + com.redhat.thermostat.vm.cpu.agent + + + com.redhat.thermostat.vm.cpu.agent.internal + + + <_nouses>true + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-vm-cpu-common + ${project.version} + + + com.redhat.thermostat + thermostat-agent-core + ${project.version} + + + com.redhat.thermostat + thermostat-storage-core + ${project.version} + + + diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/Activator.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,101 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BackendService; +import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class Activator implements BundleActivator { + + private ScheduledExecutorService executor; + private MultipleServiceTracker tracker; + private VmCpuBackend backend; + private ServiceRegistration reg; + + @Override + public void start(final BundleContext context) throws Exception { + executor = Executors.newSingleThreadScheduledExecutor(); + + Class[] deps = new Class[] { + BackendService.class, + VmCpuStatDAO.class + }; + tracker = new MultipleServiceTracker(context, deps, new Action() { + + @Override + public void dependenciesAvailable(Map services) { + VmCpuStatDAO vmCpuStatDao = (VmCpuStatDAO) services.get(VmCpuStatDAO.class.getName()); + Version version = new Version(context.getBundle()); + backend = new VmCpuBackend(executor, vmCpuStatDao, version); + reg = context.registerService(Backend.class.getName(), backend, null); + } + + @Override + public void dependenciesUnavailable() { + if (backend.isActive()) { + backend.deactivate(); + } + reg.unregister(); + } + }); + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + + /* + * For testing purposes only. + */ + VmCpuBackend getBackend() { + return backend; + } +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfo.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,73 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +public class ProcessStatusInfo { + + /* All times are measured in clock ticks */ + + private final int pid; + private final long userTime; + private final long kernelTime; + + public ProcessStatusInfo(int pid, long userTime, long kernelTime) { + this.pid = pid; + this.userTime = userTime; + this.kernelTime = kernelTime; + } + + public int getPid() { + return pid; + } + + /** + * @return the time this process has spent in user-mode as a number of + * kernel ticks + */ + public long getUserTime() { + return userTime; + } + + /** + * @return the time this process spent in kernel-mode as a number of kernel + * ticks + */ + public long getKernelTime() { + return kernelTime; + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilder.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,119 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Scanner; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.utils.ProcDataSource; + +/** + * Extract status information about the process from /proc/. This is what tools + * like {@code ps} and {@code top} use. + * + * @see {@code proc(5)} + */ +public class ProcessStatusInfoBuilder { + + private static final Logger logger = LoggingUtils.getLogger(ProcessStatusInfoBuilder.class); + + private final ProcDataSource dataSource; + + public ProcessStatusInfoBuilder(ProcDataSource dataSource) { + this.dataSource = dataSource; + } + + public ProcessStatusInfo build(int pid) { + try (BufferedReader reader = new BufferedReader(dataSource.getStatReader(pid))) { + return build(reader); + } catch (IOException e) { + logger.log(Level.WARNING, "unable to read stat info for " + pid); + } + + return null; + } + + private ProcessStatusInfo build(Reader r) throws IOException { + + int pid = -1; + long utime = -1; + long stime = -1; + + Scanner scanner = null; + + /* TODO map these (effectively c) data types to java types more sanely */ + + try (BufferedReader reader = new BufferedReader(r)) { + String statusLine = reader.readLine(); + + /* be prepared for process names like '1 ) 2 3 4 foo 5' */ + + scanner = new Scanner(statusLine); + pid = scanner.nextInt(); + scanner.close(); + + int execEndNamePos = statusLine.lastIndexOf(')'); + + String cleanStatusLine = statusLine.substring(execEndNamePos + 1); + + scanner = new Scanner(cleanStatusLine); + /* state = */scanner.next(); + /* ppid = */scanner.nextInt(); + /* pgrp = */scanner.nextInt(); + /* session = */scanner.nextInt(); + /* tty_nr = */scanner.nextInt(); + /* tpgid = */scanner.nextInt(); + /* flags = */scanner.nextInt(); + /* minflt = */scanner.nextLong(); + /* cminflt = */scanner.nextLong(); + /* majflt = */scanner.nextLong(); + /* cmajflt = */scanner.nextLong(); + utime = scanner.nextLong(); + stime = scanner.nextLong(); + scanner.close(); + } + + return new ProcessStatusInfo(pid, utime, stime); + + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackend.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,211 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import sun.jvmstat.monitor.HostIdentifier; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BackendID; +import com.redhat.thermostat.backend.BackendsProperties; +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.common.SystemClock; +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.utils.ProcDataSource; +import com.redhat.thermostat.utils.SysConf; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class VmCpuBackend extends Backend { + + private static final Logger LOGGER = LoggingUtils.getLogger(VmCpuBackend.class); + static final long PROC_CHECK_INTERVAL = 1000; // TODO make this configurable. + + private VmCpuStatBuilder vmCpuStatBuilder; + private VmCpuStatDAO vmCpuStats; + private ScheduledExecutorService executor; + private HostIdentifier hostId; + private MonitoredHost host; + private VmCpuHostListener hostListener; + private boolean started; + + public VmCpuBackend(ScheduledExecutorService executor, VmCpuStatDAO vmCpuStatDao, Version version) { + super(new BackendID("VM CPU Backend", VmCpuBackend.class.getName())); + this.executor = executor; + this.vmCpuStats = vmCpuStatDao; + + setConfigurationValue(BackendsProperties.VENDOR.name(), "Red Hat, Inc."); + setConfigurationValue(BackendsProperties.DESCRIPTION.name(), "Gathers CPU statistics about a JVM"); + setConfigurationValue(BackendsProperties.VERSION.name(), version.getVersionNumber()); + + Clock clock = new SystemClock(); + long ticksPerSecond = SysConf.getClockTicksPerSecond(); + ProcDataSource source = new ProcDataSource(); + ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(new ProcDataSource()); + int numCpus = getCpuCount(source); + vmCpuStatBuilder = new VmCpuStatBuilder(clock, numCpus, ticksPerSecond, builder); + + try { + hostId = new HostIdentifier((String) null); + host = MonitoredHost.getMonitoredHost(hostId); + hostListener = new VmCpuHostListener(vmCpuStatBuilder); + } catch (MonitorException me) { + LOGGER.log(Level.WARNING, "Problems with connecting jvmstat to local machine", me); + } catch (URISyntaxException use) { + LOGGER.log(Level.WARNING, "Failed to create host identifier", use); + } + } + + @Override + public boolean activate() { + if (!started && host != null) { + executor.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + for (Integer pid : hostListener.getPidsToMonitor()) { + if (vmCpuStatBuilder.knowsAbout(pid)) { + VmCpuStat dataBuilt = vmCpuStatBuilder.build(pid); + if (dataBuilt != null) { + vmCpuStats.putVmCpuStat(dataBuilt); + } + } else { + vmCpuStatBuilder.learnAbout(pid); + } + } + } + }, 0, PROC_CHECK_INTERVAL, TimeUnit.MILLISECONDS); + + try { + host.addHostListener(hostListener); + started = true; + } catch (MonitorException me) { + LOGGER.log(Level.WARNING, "Failed to add host listener", me); + } + + } + return started; + } + + @Override + public boolean deactivate() { + if (started && host != null) { + executor.shutdown(); + + try { + host.removeHostListener(hostListener); + started = false; + } catch (MonitorException me) { + LOGGER.log(Level.INFO, "Failed to remove host listener"); + } + } + return !started; + } + + @Override + public boolean isActive() { + return started; + } + + @Override + protected void setDAOFactoryAction() { + // No need for DAOFactory + } + + @Override + public String getConfigurationValue(String key) { + return null; + } + + @Override + public boolean attachToNewProcessByDefault() { + return true; + } + + @Override + public int getOrderValue() { + return ORDER_CPU_GROUP + 50; + } + + private int getCpuCount(ProcDataSource dataSource) { + final String KEY_PROCESSOR_ID = "processor"; + int cpuCount = 0; + try (BufferedReader bufferedReader = new BufferedReader(dataSource.getCpuInfoReader())) { + String line = null; + while ((line = bufferedReader.readLine()) != null) { + if (line.startsWith(KEY_PROCESSOR_ID)) { + cpuCount++; + } + } + } catch (IOException ioe) { + LOGGER.log(Level.WARNING, "Unable to read cpu info"); + } + + return cpuCount; + } + + /* + * For testing purposes only. + */ + void setHost(MonitoredHost host) { + this.host = host; + } + + /* + * For testing purposes only. + */ + void setVmCpuStatBuilder(VmCpuStatBuilder vmCpuStatBuilder) { + this.vmCpuStatBuilder = vmCpuStatBuilder; + } + + /* + * For testing purposes only. + */ + void setHostListener(VmCpuHostListener hostListener) { + this.hostListener = hostListener; + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuHostListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuHostListener.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,85 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.logging.Logger; + +import sun.jvmstat.monitor.event.HostEvent; +import sun.jvmstat.monitor.event.HostListener; +import sun.jvmstat.monitor.event.VmStatusChangeEvent; + +import com.redhat.thermostat.common.utils.LoggingUtils; + +public class VmCpuHostListener implements HostListener { + + private static final Logger LOGGER = LoggingUtils.getLogger(VmCpuHostListener.class); + + private final Set pidsToMonitor = new CopyOnWriteArraySet(); + private VmCpuStatBuilder vmCpuStatBuilder; + + public VmCpuHostListener(VmCpuStatBuilder builder) { + this.vmCpuStatBuilder = builder; + } + + @Override + public void vmStatusChanged(VmStatusChangeEvent event) { + for (Object newVm : event.getStarted()) { + Integer vmId = (Integer) newVm; + LOGGER.fine("New vm: " + vmId); + pidsToMonitor.add(vmId); + } + + for (Object stoppedVm : event.getTerminated()) { + Integer vmId = (Integer) stoppedVm; + LOGGER.fine("stopped vm: " + vmId); + pidsToMonitor.remove(vmId); + vmCpuStatBuilder.forgetAbout(vmId); + } + } + + @Override + public void disconnected(HostEvent event) { + LOGGER.warning("Disconnected from host"); + } + + public Set getPidsToMonitor() { + return pidsToMonitor; + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuStatBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/main/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuStatBuilder.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,130 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.storage.model.VmCpuStat; + +public class VmCpuStatBuilder { + + private static final Logger logger = LoggingUtils.getLogger(VmCpuStatBuilder.class); + + // pid -> ticks + private final Map lastProcessTicks = new HashMap(); + // pid -> last time the ticks were updated + private final Map lastProcessTickTime = new HashMap(); + + private final Clock clock; + private final int cpuCount; + private final long ticksPerSecond; + private final ProcessStatusInfoBuilder statusBuilder; + + public VmCpuStatBuilder(Clock clock, int cpuCount, long ticksPerSecond, ProcessStatusInfoBuilder statusBuilder) { + this.clock = clock; + this.cpuCount = cpuCount; + this.ticksPerSecond = ticksPerSecond; + this.statusBuilder = statusBuilder; + } + + /** + * @param pid the process id + * @return an object representing the cpu usage of the process, or null if + * the information can not be found. + */ + public synchronized VmCpuStat build(Integer pid) { + if (!lastProcessTicks.containsKey(pid) || !lastProcessTickTime.containsKey(pid)) { + throw new IllegalArgumentException("unknown pid"); + } + + ProcessStatusInfo info = statusBuilder.build(pid); + if (info == null) { + return null; + } + long miliTime = clock.getRealTimeMillis(); + long time = clock.getMonotonicTimeNanos(); + long programTicks = (info.getKernelTime() + info.getUserTime()); + double cpuLoad = 0.0; + + double timeDelta = (time - lastProcessTickTime.get(pid)) * 1E-9; + long programTicksDelta = programTicks - lastProcessTicks.get(pid); + // 100 as in 100 percent. + cpuLoad = programTicksDelta * (100.0 / timeDelta / ticksPerSecond / cpuCount); + + if (cpuLoad < 0.0 || cpuLoad > 100.0) { + logger.log(Level.WARNING, "cpu load for " + pid + " is outside [0,100]: " + cpuLoad); + logger.log(Level.WARNING, " (" + pid + ") programTicks: " + programTicks); + logger.log(Level.WARNING, " (" + pid + ") programTicksDelta: " + programTicksDelta); + logger.log(Level.WARNING, " (" + pid + ") time: " + time); + logger.log(Level.WARNING, " (" + pid + ") timeDelta: " + timeDelta); + logger.log(Level.WARNING, " (" + pid + ") ticksPerSecond: " + ticksPerSecond); + logger.log(Level.WARNING, " (" + pid + ") cpuCount: " + cpuCount); + } + + lastProcessTicks.put(pid, programTicks); + lastProcessTickTime.put(pid, time); + + return new VmCpuStat(miliTime, pid, cpuLoad); + } + + public synchronized boolean knowsAbout(int pid) { + return (lastProcessTickTime.containsKey(pid) && lastProcessTicks.containsKey(pid)); + } + + public synchronized void learnAbout(int pid) { + long time = clock.getMonotonicTimeNanos(); + ProcessStatusInfo info = statusBuilder.build(pid); + if (info == null) { + logger.log(Level.WARNING, "can not learn about pid " + pid + " : statusBuilder returned null"); + return; + } + + lastProcessTickTime.put(pid, time); + lastProcessTicks.put(pid, info.getUserTime()+ info.getKernelTime()); + } + + public synchronized void forgetAbout(int pid) { + lastProcessTicks.remove(pid); + lastProcessTickTime.remove(pid); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/ActivatorTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,104 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.Version; + +import com.redhat.thermostat.backend.Backend; +import com.redhat.thermostat.backend.BackendService; +import com.redhat.thermostat.test.StubBundleContext; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class ActivatorTest { + + @Test + public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { + StubBundleContext context = new StubBundleContext(); + + Activator activator = new Activator(); + + activator.start(context); + + assertEquals(0, context.getAllServices().size()); + assertEquals(2, context.getServiceListeners().size()); + + activator.stop(context); + } + + @Test + public void verifyActivatorRegistersServices() throws Exception { + StubBundleContext context = new StubBundleContext() { + @Override + public Bundle getBundle() { + Bundle result = mock(Bundle.class); + when(result.getVersion()).thenReturn(Version.emptyVersion); + return result; + } + }; + + BackendService service = mock(BackendService.class); + VmCpuStatDAO vmCpuStatDAO = mock(VmCpuStatDAO.class); + + context.registerService(BackendService.class.getName(), service, null); + context.registerService(VmCpuStatDAO.class, vmCpuStatDAO, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(Backend.class.getName(), VmCpuBackend.class)); + VmCpuBackend backend = activator.getBackend(); + assertNotNull(backend); + + activator.stop(context); + + assertFalse(backend.isActive()); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(2, context.getAllServices().size()); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/ProcessStatusInfoBuilderTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,144 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.StringReader; + +import org.junit.Test; + +import com.redhat.thermostat.utils.ProcDataSource; +import com.redhat.thermostat.vm.cpu.agent.internal.ProcessStatusInfo; +import com.redhat.thermostat.vm.cpu.agent.internal.ProcessStatusInfoBuilder; + +public class ProcessStatusInfoBuilderTest { + + @Test + public void testSimpleProcessStatus() { + ProcDataSource dataSource = new ProcDataSource(); + ProcessStatusInfo stat = new ProcessStatusInfoBuilder(dataSource).build(1); + assertNotNull(stat); + } + + @Test + public void testKnownProcessStatus() throws IOException { + final int PID = 10363; + String PROCESS_NAME = "(bash)"; + String STATE = "S"; + String PPID = "1737"; + String PROCESS_GROUP_ID = "10363"; + String SESSION_ID = "10363"; + String TTY_NUMBER = "34817"; + String TTY_PROCESS_GROUP_ID = "11404"; + String FLAGS_WORD = "4202496"; + String MINOR_FAULTS = "8093"; + String MINOR_FAULTS_CHILDREN = "607263"; + String MAJOR_FAULTS = "1"; + String MAJOR_FAULTS_CHILDREN = "251"; + final long USER_TIME_TICKS = 21; + final long KERNEL_TIME_TICKS = 7; + final long USER_TIME_CHILDREN = 10; + String KERNEL_TIME_CHILDREN = "1000"; + String PRIORITY = "20"; + String statString = "" + + PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " " + + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " " + + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " " + + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " + + USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " + + KERNEL_TIME_CHILDREN + " " + PRIORITY; + + ProcDataSource dataSource = mock(ProcDataSource.class); + when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString)); + ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(dataSource); + ProcessStatusInfo stat = builder.build(PID); + + verify(dataSource).getStatReader(PID); + assertNotNull(stat); + assertEquals(PID, stat.getPid()); + assertEquals(USER_TIME_TICKS, stat.getUserTime()); + assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime()); + } + + @Test + public void testBadProcessName() throws IOException { + final int PID = 10363; + String PROCESS_NAME = "(secretly-bad process sleep 10 20 ) 6)"; + String STATE = "S"; + String PPID = "1737"; + String PROCESS_GROUP_ID = "10363"; + String SESSION_ID = "10363"; + String TTY_NUMBER = "34817"; + String TTY_PROCESS_GROUP_ID = "11404"; + String FLAGS_WORD = "4202496"; + String MINOR_FAULTS = "8093"; + String MINOR_FAULTS_CHILDREN = "607263"; + String MAJOR_FAULTS = "1"; + String MAJOR_FAULTS_CHILDREN = "251"; + final long USER_TIME_TICKS = 21; + final long KERNEL_TIME_TICKS = 7; + final long USER_TIME_CHILDREN = 10; + String KERNEL_TIME_CHILDREN = "1000"; + String PRIORITY = "20"; + String statString = "" + + PID + " " + PROCESS_NAME + " " + STATE + " " + PPID + " " + + PROCESS_GROUP_ID + " " + SESSION_ID + " " + TTY_NUMBER + " " + + TTY_PROCESS_GROUP_ID + " " + FLAGS_WORD + " " + MINOR_FAULTS + " " + + MINOR_FAULTS_CHILDREN + " " + MAJOR_FAULTS + " " + MAJOR_FAULTS_CHILDREN + " " + + USER_TIME_TICKS + " " + KERNEL_TIME_TICKS + " " + USER_TIME_CHILDREN + " " + + KERNEL_TIME_CHILDREN + " " + PRIORITY; + + ProcDataSource dataSource = mock(ProcDataSource.class); + when(dataSource.getStatReader(any(Integer.class))).thenReturn(new StringReader(statString)); + ProcessStatusInfoBuilder builder = new ProcessStatusInfoBuilder(dataSource); + ProcessStatusInfo stat = builder.build(PID); + + verify(dataSource).getStatReader(PID); + assertNotNull(stat); + assertEquals(PID, stat.getPid()); + assertEquals(USER_TIME_TICKS, stat.getUserTime()); + assertEquals(KERNEL_TIME_TICKS, stat.getKernelTime()); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackendTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuBackendTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,128 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.event.HostListener; + +import com.redhat.thermostat.common.Version; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class VmCpuBackendTest { + + private VmCpuBackend backend; + private ScheduledExecutorService executor; + private MonitoredHost host; + private VmCpuStatDAO vmCpuStatDao; + + @Before + public void setup() { + executor = mock(ScheduledExecutorService.class); + vmCpuStatDao = mock(VmCpuStatDAO.class); + + Version version = mock(Version.class); + when(version.getVersionNumber()).thenReturn("0.0.0"); + + backend = new VmCpuBackend(executor, vmCpuStatDao, version); + + host = mock(MonitoredHost.class); + backend.setHost(host); + } + + @Test + public void testStart() throws MonitorException { + // Setup Runnable mocks + final Set pids = new HashSet<>(); + pids.add(0); + pids.add(1); + VmCpuHostListener listener = mock(VmCpuHostListener.class); + when(listener.getPidsToMonitor()).thenReturn(pids); + backend.setHostListener(listener); + + VmCpuStatBuilder builder = mock(VmCpuStatBuilder.class); + VmCpuStat stat0 = mock(VmCpuStat.class); + VmCpuStat stat1 = mock(VmCpuStat.class); + when(builder.build(0)).thenReturn(stat0); + when(builder.build(1)).thenReturn(stat1); + backend.setVmCpuStatBuilder(builder); + + backend.activate(); + ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(executor).scheduleAtFixedRate(captor.capture(), any(Long.class), any(Long.class), any(TimeUnit.class)); + assertTrue(backend.isActive()); + verify(host).addHostListener(any(HostListener.class)); + + Runnable runnable = captor.getValue(); + runnable.run(); + verify(builder).learnAbout(0); + verify(builder).learnAbout(1); + + when(builder.knowsAbout(anyInt())).thenReturn(true); + runnable.run(); + verify(vmCpuStatDao).putVmCpuStat(stat0); + verify(vmCpuStatDao).putVmCpuStat(stat1); + } + + @Test + public void testStop() throws MonitorException { + backend.activate(); + backend.deactivate(); + verify(executor).shutdown(); + assertFalse(backend.isActive()); + verify(host).removeHostListener(any(HostListener.class)); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuHostListenerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuHostListenerTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,106 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; + +import sun.jvmstat.monitor.event.VmStatusChangeEvent; + +public class VmCpuHostListenerTest { + + private VmCpuHostListener hostListener; + private VmCpuStatBuilder builder; + + @Before + public void setup() { + builder = mock(VmCpuStatBuilder.class); + + hostListener = new VmCpuHostListener(builder); + } + + @Test + public void testNewVM() throws InterruptedException { + startVMs(); + + // Check that pids are added to set + Set pids = hostListener.getPidsToMonitor(); + assertTrue(pids.contains(1)); + assertTrue(pids.contains(2)); + } + + @Test + public void testStoppedVM() throws InterruptedException { + final Set stopped = new HashSet<>(); + stopped.add(1); + + startVMs(); + + // Trigger a change event + VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); + when(event.getStarted()).thenReturn(Collections.emptySet()); + when(event.getTerminated()).thenReturn(stopped); + hostListener.vmStatusChanged(event); + + // Ensure only 1 removed + verify(builder).forgetAbout(1); + verify(builder, never()).forgetAbout(2); + } + + private void startVMs() throws InterruptedException { + final Set started = new HashSet<>(); + started.add(1); + started.add(2); + + // Trigger a change event + VmStatusChangeEvent event = mock(VmStatusChangeEvent.class); + when(event.getStarted()).thenReturn(started); + when(event.getTerminated()).thenReturn(Collections.emptySet()); + hostListener.vmStatusChanged(event); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuStatBuilderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/agent/src/test/java/com/redhat/thermostat/vm/cpu/agent/internal/VmCpuStatBuilderTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,171 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.agent.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Test; + +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.test.Bug; +import com.redhat.thermostat.vm.cpu.agent.internal.ProcessStatusInfo; +import com.redhat.thermostat.vm.cpu.agent.internal.ProcessStatusInfoBuilder; +import com.redhat.thermostat.vm.cpu.agent.internal.VmCpuStatBuilder; + +public class VmCpuStatBuilderTest { + + @Test + public void testBuilderKnowsNothing() { + Clock clock = mock(Clock.class); + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + int cpuCount = 0; + long ticksPerSecond = 0; + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, statusBuilder); + + assertFalse(builder.knowsAbout(0)); + assertFalse(builder.knowsAbout(1)); + assertFalse(builder.knowsAbout(Integer.MIN_VALUE)); + assertFalse(builder.knowsAbout(Integer.MAX_VALUE)); + + } + + @Test(expected = IllegalArgumentException.class) + public void testBuilderThrowsOnBuildOfUnknownPid() { + Clock clock = mock(Clock.class); + int cpuCount = 0; + long ticksPerSecond = 0; + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, statusBuilder); + builder.build(0); + } + + @Test + public void testBuildNullOnInsufficentInformation() { + int PID = 0; + int cpuCount = 0; + long ticksPerSecond = 0; + final long CLOCK1 = 10000; + final long CLOCK2 = 20000; + final ProcessStatusInfo initialInfo = new ProcessStatusInfo(PID, 1, 2); + final ProcessStatusInfo laterInfo = null; + + Clock clock = mock(Clock.class); + when(clock.getMonotonicTimeNanos()).thenReturn((long) (CLOCK1 * 1E6)).thenReturn((long) (CLOCK2 * 1E6)); + + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + when(statusBuilder.build(any(Integer.class))).thenReturn(initialInfo).thenReturn(laterInfo).thenReturn(null); + + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, cpuCount, ticksPerSecond, statusBuilder); + + builder.learnAbout(PID); + assertEquals(null, builder.build(PID)); + } + + @Test + public void testSaneBuild() { + final int PID = 0; + + final int CPU_COUNT = 3; + + final long USER_INITIAL_TICKS = 1; + final long KERNEL_INITIAL_TICKS = 1; + + final long USER_LATER_TICKS = 10; + final long KERNEL_LATER_TICKS = 10; + + final long CLOCK1 = 10000; + final long CLOCK2 = 20000; + + final long TICKS_PER_SECOND = 100; + + final double CPU_LOAD_PERCENT = + 100.0 + * ((USER_LATER_TICKS + KERNEL_LATER_TICKS) - (USER_INITIAL_TICKS + KERNEL_INITIAL_TICKS)) + / TICKS_PER_SECOND + / ((CLOCK2 - CLOCK1) * 1E-3 /* millis to seconds */) + / CPU_COUNT; + + final ProcessStatusInfo initialInfo = new ProcessStatusInfo(PID, USER_INITIAL_TICKS, KERNEL_INITIAL_TICKS); + final ProcessStatusInfo laterInfo = new ProcessStatusInfo(PID, USER_LATER_TICKS, KERNEL_LATER_TICKS); + + Clock clock = mock(Clock.class); + when(clock.getRealTimeMillis()).thenReturn(CLOCK2); + when(clock.getMonotonicTimeNanos()).thenReturn((long) (CLOCK1 * 1E6)).thenReturn((long) (CLOCK2 * 1E6)); + + ProcessStatusInfoBuilder statusBuilder = mock(ProcessStatusInfoBuilder.class); + when(statusBuilder.build(any(Integer.class))).thenReturn(initialInfo).thenReturn(laterInfo).thenReturn(null); + + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, CPU_COUNT, TICKS_PER_SECOND, statusBuilder); + + builder.learnAbout(PID); + VmCpuStat stat = builder.build(PID); + + assertNotNull(stat); + assertEquals(PID, stat.getVmId()); + assertEquals(CLOCK2, stat.getTimeStamp()); + assertEquals(CPU_LOAD_PERCENT, stat.getCpuLoad(), 0.0001); + } + + @Bug(id="1051", + summary="Avoid exceptions when reading /proc/ for dead processes", + url="http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1051") + @Test + public void testNoExceptionForBuilderLearningAboutDeadProcess() { + Clock clock = mock(Clock.class); + when(clock.getMonotonicTimeNanos()).thenReturn((long) (10000 * 1E6)); + ProcessStatusInfoBuilder procBuilder = mock(ProcessStatusInfoBuilder.class); + // This thing returns null if the /proc entry goes away. Rather than try to + // 'guess' at a pid that will not be present during test, just mock this. + when(procBuilder.build(any(Integer.class))).thenReturn(null); + VmCpuStatBuilder builder = new VmCpuStatBuilder(clock, 3, 100, procBuilder); + // If we can't handle a process' /proc entry disappearing, the next line + // will throw exception. If it does not, then we are okay. + try { + builder.learnAbout(0); + } catch (Exception e) { + // Shouldn't happen. + assertTrue(false); + } + } +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/client-core/pom.xml --- a/vm-cpu/client-core/pom.xml Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/client-core/pom.xml Mon Jan 07 15:48:38 2013 -0500 @@ -71,5 +71,10 @@ ${project.version} test + + com.redhat.thermostat + thermostat-vm-cpu-common + ${project.version} + diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuService.java --- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuService.java Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/VmCpuService.java Mon Jan 07 15:48:38 2013 -0500 @@ -41,10 +41,10 @@ import com.redhat.thermostat.client.core.NameMatchingRefFilter; import com.redhat.thermostat.client.core.controllers.InformationServiceController; import com.redhat.thermostat.common.ApplicationService; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.utils.OSGIUtils; import com.redhat.thermostat.vm.cpu.client.core.internal.VmCpuController; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class VmCpuService implements InformationService { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/Activator.java --- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/Activator.java Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/Activator.java Mon Jan 07 15:48:38 2013 -0500 @@ -50,9 +50,9 @@ import com.redhat.thermostat.common.Constants; import com.redhat.thermostat.common.MultipleServiceTracker; import com.redhat.thermostat.common.MultipleServiceTracker.Action; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.vm.cpu.client.core.VmCpuService; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class Activator implements BundleActivator { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuController.java --- a/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuController.java Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/client-core/src/main/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuController.java Mon Jan 07 15:48:38 2013 -0500 @@ -49,7 +49,6 @@ import com.redhat.thermostat.common.NotImplementedException; import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.Timer.SchedulingType; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.storage.model.DiscreteTimeData; @@ -57,6 +56,7 @@ import com.redhat.thermostat.vm.cpu.client.core.VmCpuView; import com.redhat.thermostat.vm.cpu.client.core.VmCpuViewProvider; import com.redhat.thermostat.vm.cpu.client.locale.LocaleResources; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class VmCpuController implements InformationServiceController { private static final Translate translator = LocaleResources.createLocalizer(); diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/ActivatorTest.java --- a/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/ActivatorTest.java Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/ActivatorTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -45,9 +45,9 @@ import com.redhat.thermostat.client.core.InformationService; import com.redhat.thermostat.common.ApplicationService; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.test.StubBundleContext; import com.redhat.thermostat.vm.cpu.client.core.VmCpuService; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class ActivatorTest { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuControllerTest.java --- a/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuControllerTest.java Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/client-core/src/test/java/com/redhat/thermostat/vm/cpu/client/core/internal/VmCpuControllerTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -54,12 +54,12 @@ import com.redhat.thermostat.common.ApplicationService; import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.TimerFactory; -import com.redhat.thermostat.common.dao.VmCpuStatDAO; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.storage.model.VmCpuStat; import com.redhat.thermostat.vm.cpu.client.core.VmCpuView; import com.redhat.thermostat.vm.cpu.client.core.VmCpuViewProvider; import com.redhat.thermostat.vm.cpu.client.core.internal.VmCpuController; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; public class VmCpuControllerTest { diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/common/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/common/pom.xml Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,68 @@ + + + 4.0.0 + + thermostat-vm-cpu + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-vm-cpu-common + bundle + Thermostat VM CPU Common plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + Red Hat, Inc. + com.redhat.thermostat.vm.cpu.common + com.redhat.thermostat.vm.cpu.common.internal.Activator + + com.redhat.thermostat.vm.cpu.common + + + com.redhat.thermostat.vm.cpu.common.internal + + + <_nouses>true + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-storage-core + ${project.version} + + + diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/VmCpuStatDAO.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,57 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.common; + +import java.util.List; + +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.model.VmCpuStat; + +public interface VmCpuStatDAO { + + static final Key vmCpuLoadKey = new Key<>("cpuLoad", false); + + static final Category vmCpuStatCategory = new Category("vm-cpu-stats", + Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, vmCpuLoadKey); + + public abstract List getLatestVmCpuStats(VmRef ref, long since); + + public abstract void putVmCpuStat(VmCpuStat stat); + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/Activator.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,79 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.common.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class Activator implements BundleActivator { + + private ServiceTracker tracker; + private ServiceRegistration reg; + + @Override + public void start(BundleContext context) throws Exception { + tracker = new ServiceTracker(context, Storage.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + Storage storage = (Storage) context.getService(reference); + VmCpuStatDAO vmCpuStatDao = new VmCpuStatDAOImpl(storage); + reg = context.registerService(VmCpuStatDAO.class.getName(), vmCpuStatDao, null); + return super.addingService(reference); + } + + @Override + public void removedService(ServiceReference reference, + Object service) { + reg.unregister(); + super.removedService(reference, service); + } + }; + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImpl.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,67 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.common.internal; + +import java.util.List; + +import com.redhat.thermostat.common.dao.VmLatestPojoListGetter; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class VmCpuStatDAOImpl implements VmCpuStatDAO { + + private final Storage storage; + private final VmLatestPojoListGetter getter; + + VmCpuStatDAOImpl(Storage storage) { + this.storage = storage; + storage.registerCategory(vmCpuStatCategory); + this.getter = new VmLatestPojoListGetter<>(storage, vmCpuStatCategory, VmCpuStat.class); + } + + @Override + public List getLatestVmCpuStats(VmRef ref, long since) { + return getter.getLatest(ref, since); + } + + @Override + public void putVmCpuStat(VmCpuStat stat) { + storage.putPojo(vmCpuStatCategory, false, stat); + } +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/ActivatorTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,84 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.common.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.test.StubBundleContext; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class ActivatorTest { + + @Test + public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { + StubBundleContext context = new StubBundleContext(); + + Activator activator = new Activator(); + + activator.start(context); + + assertEquals(0, context.getAllServices().size()); + assertEquals(1, context.getServiceListeners().size()); + + activator.stop(context); + } + + @Test + public void verifyActivatorRegistersServices() throws Exception { + StubBundleContext context = new StubBundleContext(); + Storage storage = mock(Storage.class); + + context.registerService(Storage.class, storage, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(VmCpuStatDAO.class.getName(), VmCpuStatDAOImpl.class)); + + activator.stop(context); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(1, context.getAllServices().size()); + } + +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOTest.java Mon Jan 07 15:48:38 2013 -0500 @@ -0,0 +1,140 @@ +/* + * Copyright 2012 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.cpu.common.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collection; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.test.MockQuery; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class VmCpuStatDAOTest { + + private static final Long TIMESTAMP = 1234L; + private static final Integer VM_ID = 321; + private static final Double CPU_LOAD = 9.9; + + private VmCpuStat cpuStat; + + @Before + public void setUp() { + cpuStat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD); + } + + @Test + public void testCategory() { + assertEquals("vm-cpu-stats", VmCpuStatDAO.vmCpuStatCategory.getName()); + Collection> keys = VmCpuStatDAO.vmCpuStatCategory.getKeys(); + assertTrue(keys.contains(new Key<>("agentId", true))); + assertTrue(keys.contains(new Key("timeStamp", false))); + assertTrue(keys.contains(new Key("vmId", true))); + assertTrue(keys.contains(new Key("cpuLoad", false))); + assertEquals(4, keys.size()); + } + + @Test + public void testGetLatestCpuStatsBasic() { + + @SuppressWarnings("unchecked") + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(true).thenReturn(false); + when(cursor.next()).thenReturn(cpuStat); + + Storage storage = mock(Storage.class); + when(storage.createQuery()).then(new Answer() { + @Override + public Query answer(InvocationOnMock invocation) throws Throwable { + return new MockQuery(); + } + }); + when(storage.findAllPojos(any(Query.class), same(VmCpuStat.class))).thenReturn(cursor); + + HostRef hostRef = mock(HostRef.class); + when(hostRef.getAgentId()).thenReturn("system"); + + VmRef vmRef = mock(VmRef.class); + when(vmRef.getAgent()).thenReturn(hostRef); + when(vmRef.getId()).thenReturn(VM_ID); + + + VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage); + List vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE); + + ArgumentCaptor arg = ArgumentCaptor.forClass(MockQuery.class); + verify(storage).findAllPojos(arg.capture(), same(VmCpuStat.class)); + assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE)); + + assertEquals(1, vmCpuStats.size()); + VmCpuStat stat = vmCpuStats.get(0); + assertEquals(TIMESTAMP, (Long) stat.getTimeStamp()); + assertEquals(CPU_LOAD, stat.getCpuLoad(), 0.001); + assertEquals(VM_ID, (Integer) stat.getVmId()); + } + + @Test + public void testPutVmCpuStat() { + Storage storage = mock(Storage.class); + VmCpuStat stat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD); + VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage); + dao.putVmCpuStat(stat); + + verify(storage).putPojo(VmCpuStatDAO.vmCpuStatCategory, false, stat); + + } +} diff -r 4c8a876b9dc0 -r 9e6bcfc40ea1 vm-cpu/pom.xml --- a/vm-cpu/pom.xml Mon Jan 07 15:46:47 2013 -0500 +++ b/vm-cpu/pom.xml Mon Jan 07 15:48:38 2013 -0500 @@ -51,8 +51,10 @@ Thermostat VM CPU plugin + agent client-core client-swing + common