Mercurial > hg > release > thermostat-1.0
changeset 406:966e565b1d4b
Fix workflow for HeapView
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-June/001942.html
reviewed-by: omajid
PR 1033
PR 944
line wrap: on
line diff
--- a/client/heapdumper/pom.xml Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/pom.xml Wed Jun 20 23:31:53 2012 +0200 @@ -85,6 +85,12 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-common-core</artifactId> <version>${project.version}</version>
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/Activator.java Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/Activator.java Wed Jun 20 23:31:53 2012 +0200 @@ -38,14 +38,15 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceEvent; -import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.client.heap.swing.HeapSwingView; import com.redhat.thermostat.client.osgi.service.ApplicationService; -import com.redhat.thermostat.client.osgi.service.ContextAction; -import com.redhat.thermostat.client.osgi.service.VMContextAction; +import com.redhat.thermostat.client.osgi.service.VmInformationService; +import com.redhat.thermostat.common.appctx.ApplicationContext; public class Activator implements BundleActivator { @@ -54,49 +55,17 @@ @Override public void start(final BundleContext context) throws Exception { - ServiceListener listener = new ServiceListener() { - - private ApplicationService appService; - private boolean contextActionServiceLoaded; - private boolean applicationServiceLoaded; - + ServiceTracker tracker = new ServiceTracker(context, ApplicationService.class.getName(), null) { @Override - public void serviceChanged(ServiceEvent event) { + public Object addingService(ServiceReference reference) { + ApplicationService appService = (ApplicationService) context.getService(reference); - ServiceReference reference = event.getServiceReference(); - Object service = context.getService(reference); - switch (event.getType()) { - case ServiceEvent.REGISTERED: - if (service instanceof ContextAction) { - contextActionServiceLoaded = true; - } else if (service instanceof ApplicationService) { - applicationServiceLoaded = true; - appService = (ApplicationService) service; - } - break; - - default: - break; - } - - if (contextActionServiceLoaded && applicationServiceLoaded) { - contextServiceReg = context.registerService(VMContextAction.class.getName(), - new HeapDumpAction(appService.getDAOFactory(), context), null); - } + ApplicationContext.getInstance().getViewFactory().setViewClass(HeapView.class, HeapSwingView.class); + context.registerService(VmInformationService.class.getName(), new HeapDumperService(appService), null); + return super.addingService(reference); } }; - - String filter = "(|(objectClass=" + ContextAction.class.getName() + ")" - + " (objectClass=" + ApplicationService.class.getName() + "))"; - - context.addServiceListener(listener, filter); - ServiceReference[] services = context.getServiceReferences(null, null); - if (services != null) { - for (int i = 0; i < services.length; i++) { - listener.serviceChanged(new ServiceEvent( - ServiceEvent.REGISTERED, services[i])); - } - } + tracker.open(); } @Override
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpAction.java Wed Jun 20 16:45:53 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +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 - * <http://www.gnu.org/licenses/>. - * - * 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.client.heap; - -import java.util.logging.Logger; - -import org.osgi.framework.BundleContext; - -import com.redhat.thermostat.client.heap.swing.HeapSwingView; -import com.redhat.thermostat.client.osgi.service.Filter; -import com.redhat.thermostat.client.osgi.service.VMContextAction; -import com.redhat.thermostat.client.osgi.service.VmInformationService; -import com.redhat.thermostat.common.appctx.ApplicationContext; -import com.redhat.thermostat.common.dao.DAOFactory; -import com.redhat.thermostat.common.dao.Ref; -import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.common.model.VmInfo; - -/** - * Implements the {@link VMContextAction} entry point to provide a kill switch - * for the currently selected Virtual Machine. - */ -public class HeapDumpAction implements VMContextAction { - - private static final Logger log = Logger.getLogger(HeapDumpAction.class.getName()); - - private final DAOFactory dao; - private final BundleContext context; - - public HeapDumpAction(DAOFactory dao, BundleContext context) { - this.dao = dao; - this.context = context; - } - - @Override - public String getName() { - return "Heap Analysis"; - } - - @Override - public String getDescription() { - return "Heap View"; - } - - @Override - public void execute(VmRef reference) { - ApplicationContext.getInstance().getViewFactory().setViewClass(HeapView.class, HeapSwingView.class); - context.registerService(VmInformationService.class.getName(), new HeapDumperService(reference), null); - } - - @Override - public Filter getFilter() { - return new LocalAndAliveFilter(); - } - - private class LocalAndAliveFilter implements Filter { - - @Override - public boolean matches(Ref ref) { - // TODO implement local checking too - if (ref instanceof VmRef) { - VmRef vm = (VmRef) ref; - VmInfo vmInfo = dao.getVmInfoDAO().getVmInfo(vm); - return vmInfo.isAlive(); - } else { - return false; - } - } - - } -}
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java Wed Jun 20 23:31:53 2012 +0200 @@ -54,6 +54,7 @@ import com.redhat.thermostat.client.heap.HeapView.HeadDumperAction; import com.redhat.thermostat.client.heap.chart.OverviewChart; +import com.redhat.thermostat.client.osgi.service.ApplicationService; import com.redhat.thermostat.client.osgi.service.VmInformationServiceController; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; @@ -86,9 +87,11 @@ private final Timer timer; private OverviewChart model; + private ApplicationService appService; - public HeapDumpController(final VmRef ref) { + public HeapDumpController(final VmRef ref, final ApplicationService appService) { + this.appService = appService; this.ref = ref; this.vmDao = ApplicationContext.getInstance().getDAOFactory().getVmMemoryStatDAO(); this.heapDAO = ApplicationContext.getInstance().getDAOFactory().getHeapDAO(); @@ -104,7 +107,7 @@ timer.setSchedulingType(SchedulingType.FIXED_RATE); view = ApplicationContext.getInstance().getViewFactory().getView(HeapView.class); - + HeapDump dump = null; view.clearHeapDumpList(); Collection<HeapInfo> infos = heapDAO.getAllHeapInfo(ref); @@ -114,6 +117,13 @@ view.addHeapDump(dump); } + // check if we were reading some of the dumps + dump = (HeapDump) appService.getApplicationCache().getAttribute(ref); + if (dump != null && infos.contains(dump.getInfo())) { + readAndSetHistogram(dump); + view.openDumpView(dump); + } + view.addActionListener(new ActionListener<Action>() { @Override public void actionPerformed(ActionEvent<Action> actionEvent) { @@ -141,15 +151,27 @@ case DUMP_REQUESTED: dump = command.execute(ref); view.addHeapDump(dump); + + // also, only if it's the fist dump, we jump there + // it doesn't disrupt the workflow if it's the first dump + if (appService.getApplicationCache().getAttribute(ref) == null) { + analyseDump(dump); + } + break; case ANALYSE: dump = (HeapDump) actionEvent.getPayload(); - readAndSetHistogram(dump); - view.openDumpView(dump); + analyseDump(dump); break; } } + + private void analyseDump(HeapDump dump) { + readAndSetHistogram(dump); + view.openDumpView(dump); + appService.getApplicationCache().addAttribute(ref, dump); + } }); }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumperService.java Wed Jun 20 23:31:53 2012 +0200 @@ -36,25 +36,26 @@ package com.redhat.thermostat.client.heap; +import com.redhat.thermostat.client.osgi.service.ApplicationService; import com.redhat.thermostat.client.osgi.service.VmInformationService; import com.redhat.thermostat.client.osgi.service.VmInformationServiceController; import com.redhat.thermostat.common.dao.VmRef; public class HeapDumperService implements VmInformationService { - private VmRef vmRef; - - public HeapDumperService(VmRef reference) { - this.vmRef = reference; + private ApplicationService appService; + + public HeapDumperService(ApplicationService appService) { + this.appService = appService; } @Override public VmInformationServiceController getInformationServiceController(VmRef ref) { - return new HeapDumpController(ref); + return new HeapDumpController(ref, appService); } @Override public boolean isApplicableFor(VmRef ref) { - return vmRef.equals(ref); + return true; } }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapView.java Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapView.java Wed Jun 20 23:31:53 2012 +0200 @@ -48,7 +48,7 @@ ANALYSE, REQUEST_ABORTED } - + protected final ActionNotifier<HeadDumperAction> heapDumperNotifier; protected HeapView() { heapDumperNotifier = new ActionNotifier<HeadDumperAction>(this); @@ -61,7 +61,7 @@ public void removeDumperListener(ActionListener<HeadDumperAction> listener) { heapDumperNotifier.removeActionListener(listener); } - + public abstract E getComponent(); abstract public void updateOverview(OverviewChart model, String used, String capacity);
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java Wed Jun 20 23:31:53 2012 +0200 @@ -45,7 +45,6 @@ import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JPanel; -import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -55,9 +54,7 @@ import com.redhat.thermostat.client.ui.ComponentVisibleListener; public class HeapSwingView extends HeapView<JComponent> { - - private boolean heapDetailIsShowing; - + private StatsPanel stats; private HeapPanel heapDetailPanel; @@ -93,10 +90,8 @@ stats.addDumpListListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - HeapDump dump = stats.getSelectedHeapDump(); - heapDumperNotifier.fireAction(HeadDumperAction.ANALYSE, dump); - } + HeapDump dump = stats.getSelectedHeapDump(); + heapDumperNotifier.fireAction(HeadDumperAction.ANALYSE, dump); } }); @@ -172,22 +167,16 @@ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - if (!heapDetailIsShowing) { - visiblePane.removeAll(); - - heapDetailIsShowing = true; - - heapDetailPanel.divideView(); - heapDetailPanel.setTop(overview); + visiblePane.removeAll(); + heapDetailPanel.divideView(); + heapDetailPanel.setTop(overview); - HistogramPanel histogram = new HistogramPanel(); - histogram.display(dump.getHistogram()); - heapDetailPanel.setBottom(histogram); - - visiblePane.add(heapDetailPanel); - - visiblePane.revalidate(); - } + HistogramPanel histogram = new HistogramPanel(); + histogram.display(dump.getHistogram()); + heapDetailPanel.setBottom(histogram); + + visiblePane.add(heapDetailPanel); + visiblePane.revalidate(); } }); }
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/ActivatorTest.java Wed Jun 20 16:45:53 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +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 - * <http://www.gnu.org/licenses/>. - * - * 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.client.heap; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doNothing; -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.Dictionary; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Matchers; -import org.osgi.framework.BundleContext; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceEvent; -import org.osgi.framework.ServiceListener; -import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; - -import com.redhat.thermostat.client.osgi.service.ApplicationService; -import com.redhat.thermostat.client.osgi.service.ContextAction; -import com.redhat.thermostat.client.osgi.service.VMContextAction; - -public class ActivatorTest { - - private Activator activator; - private BundleContext bundleContext; - private ArgumentCaptor<ServiceListener> serviceListener; - private ServiceReference ref1; - private ContextAction service1; - private ServiceReference ref2; - private ApplicationService service2; - private ServiceReference ref3; - - @Before - public void setUp() throws InvalidSyntaxException { - activator = new Activator(); - bundleContext = mock(BundleContext.class); - serviceListener = ArgumentCaptor.forClass(ServiceListener.class); - doNothing().when(bundleContext).addServiceListener(serviceListener.capture(), anyString()); - ref1 = mock(ServiceReference.class); - service1 = mock(ContextAction.class); - when(bundleContext.getService(ref1)).thenReturn(service1); - ref2 = mock(ServiceReference.class); - service2 = mock(ApplicationService.class); - when(bundleContext.getService(ref2)).thenReturn(service2); - ref3 = mock(ServiceReference.class); - when(bundleContext.getService(ref3)).thenReturn(new Object()); - } - - @Test - public void testStart() throws Exception { - activator.start(bundleContext); - verifyRegistration(false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref1, false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref2, true); - } - - @Test - public void testStartAppServiceFirst() throws Exception { - activator.start(bundleContext); - verifyRegistration(false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref2, false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref1, true); - } - - @Test - public void testStartOtherService() throws Exception { - activator.start(bundleContext); - verifyRegistration(false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref2, false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref3, false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref1, true); - } - - @Test - public void testStartDifferentEventType() throws Exception { - activator.start(bundleContext); - verifyRegistration(false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref2, false); - fireServiceEventAndVerifyRegistration(ServiceEvent.MODIFIED, ref1, false); - fireServiceEventAndVerifyRegistration(ServiceEvent.REGISTERED, ref1, true); - } - - @Test - public void testStartExistingServices() throws Exception { - - when(bundleContext.getServiceReferences(null, null)).thenReturn(new ServiceReference[] { ref1, ref2 }); - - activator.start(bundleContext); - - verifyRegistration(true); - } - - @Test - public void testStop() throws Exception { - ServiceRegistration serviceReg = mock(ServiceRegistration.class); - when(bundleContext.registerService(eq(VMContextAction.class.getName()), any(), any(Dictionary.class))).thenReturn(serviceReg); - testStart(); // Performs all the registration tasks. - verify(serviceReg, never()).unregister(); - activator.stop(bundleContext); - verify(serviceReg).unregister(); - } - - @Test - public void testStopIncompleteRegistration() throws Exception { - ServiceRegistration serviceReg = mock(ServiceRegistration.class); - when(bundleContext.registerService(eq(VMContextAction.class.getName()), any(), any(Dictionary.class))).thenReturn(serviceReg); - - activator.start(bundleContext); - fireServiceEvent(ServiceEvent.REGISTERED, ref2); - verify(serviceReg, never()).unregister(); - - activator.stop(bundleContext); - verify(serviceReg, never()).unregister(); - } - - private void fireServiceEventAndVerifyRegistration(int type, ServiceReference ref, boolean expectRegisterCalled) { - fireServiceEvent(type, ref); - verifyRegistration(expectRegisterCalled); - } - - private void fireServiceEvent(int type, ServiceReference ref) { - ServiceEvent event = new ServiceEvent(type, ref); - serviceListener.getValue().serviceChanged(event); - } - - private void verifyRegistration(boolean expectRegisterCalled) { - if (expectRegisterCalled) { - verify(bundleContext).registerService(eq(VMContextAction.class.getName()), Matchers.isA(HeapDumpAction.class), any(Dictionary.class)); - } else { - verify(bundleContext, never()).registerService(anyString(), any(), any(Dictionary.class)); - } - } - -}
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpActionTest.java Wed Jun 20 16:45:53 2012 -0400 +++ /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 - * <http://www.gnu.org/licenses/>. - * - * 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.client.heap; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.osgi.framework.BundleContext; - -import com.redhat.thermostat.client.osgi.service.Filter; -import com.redhat.thermostat.common.dao.DAOFactory; -import com.redhat.thermostat.common.dao.Ref; -import com.redhat.thermostat.common.dao.VmInfoDAO; -import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.common.model.VmInfo; - -public class HeapDumpActionTest { - - private HeapDumpAction heapDumpAction; - private DAOFactory dao; - private VmRef aliveVmRef; - private VmRef deadVmRef; - - @Before - public void setUp() { - dao = mock(DAOFactory.class); - VmInfoDAO vmInfoDAO = mock(VmInfoDAO.class); - when(dao.getVmInfoDAO()).thenReturn(vmInfoDAO); - - VmInfo vmInfo1 = mock(VmInfo.class); - when(vmInfo1.isAlive()).thenReturn(true); - aliveVmRef = mock(VmRef.class); - when(vmInfoDAO.getVmInfo(aliveVmRef)).thenReturn(vmInfo1); - - VmInfo vmInfo2 = mock(VmInfo.class); - when(vmInfo2.isAlive()).thenReturn(false); - deadVmRef = mock(VmRef.class); - when(vmInfoDAO.getVmInfo(deadVmRef)).thenReturn(vmInfo2); - - - BundleContext bundleContext = mock(BundleContext.class); - heapDumpAction = new HeapDumpAction(dao, bundleContext); - } - - @After - public void tearDown() { - heapDumpAction = null; - deadVmRef = null; - aliveVmRef = null; - dao = null; - } - - @Test - public void testName() { - assertEquals("Heap Analysis", heapDumpAction.getName()); - } - - @Test - public void testDescription() { - assertEquals("Heap View", heapDumpAction.getDescription()); - } - - @Test - public void testFilter() { - Filter filter = heapDumpAction.getFilter(); - assertTrue(filter.matches(aliveVmRef)); - assertFalse(filter.matches(deadVmRef)); - assertFalse(filter.matches(mock(Ref.class))); - } - - @Test - public void testExec() throws IOException { - // TODO: Not tested yet. We cannot mock Runtime.exec(), not even with PowerMock. - // We should create a wrapper API (that needs to remain untested, and for this - // reason should be *really* dumb), against which we can test. - } -}
--- a/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java Wed Jun 20 16:45:53 2012 -0400 +++ b/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java Wed Jun 20 23:31:53 2012 +0200 @@ -43,8 +43,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.times; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import javax.swing.JComponent; @@ -54,7 +56,10 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.mockito.internal.verification.Times; +import com.redhat.thermostat.client.osgi.service.ApplicationCache; +import com.redhat.thermostat.client.osgi.service.ApplicationService; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.Timer; @@ -67,6 +72,7 @@ import com.redhat.thermostat.common.dao.MongoDAOFactory; import com.redhat.thermostat.common.dao.VmClassStatDAO; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.model.HeapInfo; import com.redhat.thermostat.common.model.VmClassStat; public class HeapDumpControllerTest { @@ -76,9 +82,11 @@ private Timer timer; + private HeapDAO heapDao; private HeapView<JComponent> view; private HeapDumpController controller; + private ApplicationService appService; @Before public void setUp() { @@ -88,15 +96,13 @@ DAOFactory daoFactory = mock(MongoDAOFactory.class); when(daoFactory.getVmClassStatsDAO()).thenReturn(vmClassStatDAO); - HeapDAO heapDao = mock(HeapDAO.class); + heapDao = mock(HeapDAO.class); when(daoFactory.getHeapDAO()).thenReturn(heapDao); ApplicationContext.getInstance().setDAOFactory(daoFactory); setUpTimers(); setUpView(); - - setUpListeners(); } private void setUpTimers() { @@ -118,32 +124,118 @@ ApplicationContext.getInstance().setViewFactory(viewFactory); } - private void setUpListeners() { + private void setUpListeners() { ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class); doNothing().when(view).addActionListener(viewArgumentCaptor1.capture()); ArgumentCaptor<ActionListener> viewArgumentCaptor2 = ArgumentCaptor.forClass(ActionListener.class); doNothing().when(view).addDumperListener(viewArgumentCaptor2.capture()); - - VmRef ref = mock(VmRef.class); - controller = new HeapDumpController(ref); + + createController(); actionListener = viewArgumentCaptor1.getValue(); heapDumperListener = viewArgumentCaptor2.getValue(); } + private void createController() { + ApplicationCache cache = mock(ApplicationCache.class); + appService = mock(ApplicationService.class); + when(appService.getApplicationCache()).thenReturn(cache); + VmRef ref = mock(VmRef.class); + controller = new HeapDumpController(ref, appService); + } + @Test public void testTimerStartOnViewVisible() { + + setUpListeners(); + actionListener.actionPerformed(new ActionEvent<>(view, HeapView.Action.VISIBLE)); verify(timer).start(); } @Test public void testTimerStopsOnViewHidden() { + + setUpListeners(); + actionListener.actionPerformed(new ActionEvent<>(view, HeapView.Action.HIDDEN)); verify(timer).stop(); } + @Test + public void testNotAddHeapDumpsAtStartupWhenNoDumps() { + + when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(new ArrayList<HeapInfo>()); + + createController(); + + verify(view, times(0)).addHeapDump(any(HeapDump.class)); + } + + @Test + public void testAddHeapDumpsAtStartupWhenDumpsAreThere() { + HeapInfo info1 = mock(HeapInfo.class); + HeapInfo info2 = mock(HeapInfo.class); + Collection<HeapInfo> infos = new ArrayList<HeapInfo>(); + infos.add(info1); + infos.add(info2); + + when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos); + + createController(); + + verify(view, times(2)).addHeapDump(any(HeapDump.class)); + } + + @Test + public void testOpenDumpCalledWhenPreviousDump() { + + HeapDump dump = mock(HeapDump.class); + + HeapInfo info1 = mock(HeapInfo.class); + when(dump.getInfo()).thenReturn(info1); + + HeapInfo info2 = mock(HeapInfo.class); + Collection<HeapInfo> infos = new ArrayList<HeapInfo>(); + infos.add(info1); + infos.add(info2); + + when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos); + + ApplicationCache cache = mock(ApplicationCache.class); + when(cache.getAttribute(any(VmRef.class))).thenReturn(dump); + + appService = mock(ApplicationService.class); + when(appService.getApplicationCache()).thenReturn(cache); + VmRef ref = mock(VmRef.class); + controller = new HeapDumpController(ref, appService); + + verify(view, times(1)).openDumpView(dump); + } + + @Test + public void testNotOpenDumpCalledWhenNoPreviousDump() { + + HeapInfo info1 = mock(HeapInfo.class); + HeapInfo info2 = mock(HeapInfo.class); + Collection<HeapInfo> infos = new ArrayList<HeapInfo>(); + infos.add(info1); + infos.add(info2); + + when(heapDao.getAllHeapInfo(any(VmRef.class))).thenReturn(infos); + + ApplicationCache cache = mock(ApplicationCache.class); + when(cache.getAttribute(any(VmRef.class))).thenReturn(null); + + appService = mock(ApplicationService.class); + when(appService.getApplicationCache()).thenReturn(cache); + VmRef ref = mock(VmRef.class); + controller = new HeapDumpController(ref, appService); + + verify(view, times(0)).openDumpView(any(HeapDump.class)); + } + @After public void tearDown() { ApplicationContextUtil.resetApplicationContext();