changeset 2549:a4d9708db5f1

Update HeapIdCompleterService for Declarative Services Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-December/021859.html
author Andrew Azores <aazores@redhat.com>
date Fri, 16 Dec 2016 09:06:40 -0500
parents f198b30beb47
children 1a9f0dc69d14
files vm-heap-analysis/command/pom.xml vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/Activator.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdCompleterService.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinder.java vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinderImpl.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdCompleterServiceTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinderImplTest.java vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinderTest.java
diffstat 9 files changed, 321 insertions(+), 248 deletions(-) [+]
line wrap: on
line diff
--- a/vm-heap-analysis/command/pom.xml	Wed Dec 14 10:29:05 2016 -0500
+++ b/vm-heap-analysis/command/pom.xml	Fri Dec 16 09:06:40 2016 -0500
@@ -69,6 +69,18 @@
           </instructions>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-scr-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-scr-scrdescriptor</id>
+            <goals>
+              <goal>scr</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <dependencies>
@@ -102,6 +114,10 @@
       <artifactId>org.osgi.compendium</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.scr.annotations</artifactId>
+    </dependency>
     
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/Activator.java	Wed Dec 14 10:29:05 2016 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/Activator.java	Fri Dec 16 09:06:40 2016 -0500
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.vm.heap.analysis.command.internal;
 
-import com.redhat.thermostat.common.cli.CompleterService;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -68,9 +67,6 @@
         registerCommand("object-info", new ObjectInfoCommand());
         registerCommand("find-root", new FindRootCommand());
 
-        final HeapIdCompleterService completerService = new HeapIdCompleterService();
-        context.registerService(CompleterService.class.getName(), completerService, null);
-
         Class<?>[] serviceDeps = new Class<?>[] {
                 AgentInfoDAO.class,
                 VmInfoDAO.class,
@@ -86,9 +82,6 @@
                 HeapDAO heapDao = services.get(HeapDAO.class);
                 RequestQueue queue = services.get(RequestQueue.class);
 
-                completerService.setHeapDAO(heapDao);
-                completerService.setVmInfoDAO(vmDao);
-
                 dumpHeapCommand.setAgentInfoDAO(agentDao);
                 dumpHeapCommand.setVmInfoDAO(vmDao);
                 dumpHeapCommand.setHeapDAO(heapDao);
@@ -97,9 +90,6 @@
 
             @Override
             public void dependenciesUnavailable() {
-                completerService.setHeapDAO(null);
-                completerService.setVmInfoDAO(null);
-
                 dumpHeapCommand.setAgentInfoDAO(null);
                 dumpHeapCommand.setVmInfoDAO(null);
                 dumpHeapCommand.setHeapDAO(null);
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdCompleterService.java	Wed Dec 14 10:29:05 2016 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdCompleterService.java	Fri Dec 16 09:06:40 2016 -0500
@@ -36,12 +36,13 @@
 
 package com.redhat.thermostat.vm.heap.analysis.command.internal;
 
-import com.redhat.thermostat.common.cli.AbstractCompleterService;
 import com.redhat.thermostat.common.cli.CliCommandOption;
+import com.redhat.thermostat.common.cli.CompleterService;
+import com.redhat.thermostat.common.cli.CompletionFinderTabCompleter;
 import com.redhat.thermostat.common.cli.TabCompleter;
-import com.redhat.thermostat.common.cli.CompletionFinderTabCompleter;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -49,7 +50,12 @@
 import java.util.Map;
 import java.util.Set;
 
-public class HeapIdCompleterService extends AbstractCompleterService {
+@Component
+@Service
+public class HeapIdCompleterService implements CompleterService {
+
+    @Reference
+    private HeapIdsFinder heapIdsFinder;
 
     @Override
     public Set<String> getCommands() {
@@ -65,17 +71,22 @@
     @Override
     public Map<CliCommandOption, TabCompleter> getOptionCompleters() {
         CliCommandOption heapOption = new CliCommandOption("h", "heapId", true, "Heap ID", false);
-        TabCompleter heapCompleter = new CompletionFinderTabCompleter(new HeapIdsFinder(dependencyServices));
+        TabCompleter heapCompleter = new CompletionFinderTabCompleter(heapIdsFinder);
 
         return Collections.singletonMap(heapOption, heapCompleter);
     }
 
-    void setHeapDAO(HeapDAO heapDao) {
-        setService(HeapDAO.class, heapDao);
+    @Override
+    public Map<String, Map<CliCommandOption, ? extends TabCompleter>> getSubcommandCompleters() {
+        return Collections.emptyMap();
     }
 
-    void setVmInfoDAO(VmInfoDAO vmInfoDao) {
-        setService(VmInfoDAO.class, vmInfoDao);
+    public void bindHeapIdsFinder(HeapIdsFinder heapIdsFinder) {
+        this.heapIdsFinder = heapIdsFinder;
+    }
+
+    public void unbindHeapIdsFinder(HeapIdsFinder heapIdsFinder) {
+        this.heapIdsFinder = null;
     }
 
 }
\ No newline at end of file
--- a/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinder.java	Wed Dec 14 10:29:05 2016 -0500
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinder.java	Fri Dec 16 09:06:40 2016 -0500
@@ -36,60 +36,7 @@
 
 package com.redhat.thermostat.vm.heap.analysis.command.internal;
 
-import com.redhat.thermostat.common.Clock;
-import com.redhat.thermostat.common.cli.AbstractCompletionFinder;
-import com.redhat.thermostat.common.cli.CompletionInfo;
-import com.redhat.thermostat.common.cli.DependencyServices;
-import com.redhat.thermostat.shared.locale.Translate;
-import com.redhat.thermostat.storage.core.VmId;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
-import com.redhat.thermostat.vm.heap.analysis.common.model.HeapInfo;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-public class HeapIdsFinder extends AbstractCompletionFinder {
-
-    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-
-    public HeapIdsFinder(DependencyServices dependencyServices) {
-        super(dependencyServices);
-    }
-
-    @Override
-    protected Class<?>[] getRequiredDependencies() {
-        return new Class<?>[] { HeapDAO.class, VmInfoDAO.class };
-    }
+import com.redhat.thermostat.common.cli.CompletionFinder;
 
-    @Override
-    public List<CompletionInfo> findCompletions() {
-        if (!allDependenciesAvailable()) {
-            return Collections.emptyList();
-        }
-
-        HeapDAO heapDao = getService(HeapDAO.class);
-        VmInfoDAO vmDao = getService(VmInfoDAO.class);
-
-        List<CompletionInfo> heapIds = new ArrayList<>();
-        for (HeapInfo heap : heapDao.getAllHeapInfo()) {
-            CompletionInfo completionInfo = getCompletionInfo(vmDao, heap);
-            heapIds.add(completionInfo);
-        }
-        return heapIds;
-    }
-
-    private CompletionInfo getCompletionInfo(VmInfoDAO vmDao, HeapInfo heap) {
-        VmInfo vmInfo = vmDao.getVmInfo(new VmId(heap.getVmId()));
-
-        String mainclass = vmInfo.getMainClass();
-        String timestamp = Clock.DEFAULT_DATE_FORMAT.format(new Date(heap.getTimeStamp()));
-
-        String userVisibleText = t.localize(LocaleResources.HEAPID_COMPLETION_WITH_USER_TEXT, mainclass, timestamp).getContents();
-        return new CompletionInfo(heap.getHeapId(), userVisibleText);
-    }
-
+interface HeapIdsFinder extends CompletionFinder {
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/main/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinderImpl.java	Fri Dec 16 09:06:40 2016 -0500
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012-2016 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.vm.heap.analysis.command.internal;
+
+import com.redhat.thermostat.common.Clock;
+import com.redhat.thermostat.common.cli.CompletionInfo;
+import com.redhat.thermostat.shared.locale.Translate;
+import com.redhat.thermostat.storage.core.VmId;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.model.HeapInfo;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+@Component
+@Service
+public class HeapIdsFinderImpl implements HeapIdsFinder {
+
+    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
+
+    @Reference
+    private HeapDAO heapDAO;
+
+    @Reference
+    private VmInfoDAO vmInfoDAO;
+
+    @Override
+    public List<CompletionInfo> findCompletions() {
+        if (heapDAO == null || vmInfoDAO == null) {
+            return Collections.emptyList();
+        }
+
+        List<CompletionInfo> heapIds = new ArrayList<>();
+        for (HeapInfo heap : heapDAO.getAllHeapInfo()) {
+            CompletionInfo completionInfo = getCompletionInfo(heap);
+            heapIds.add(completionInfo);
+        }
+        return heapIds;
+    }
+
+    private CompletionInfo getCompletionInfo(HeapInfo heap) {
+        VmInfo vmInfo = vmInfoDAO.getVmInfo(new VmId(heap.getVmId()));
+
+        String mainclass = vmInfo.getMainClass();
+        String timestamp = Clock.DEFAULT_DATE_FORMAT.format(new Date(heap.getTimeStamp()));
+
+        String userVisibleText = t.localize(LocaleResources.HEAPID_COMPLETION_WITH_USER_TEXT, mainclass, timestamp).getContents();
+        return new CompletionInfo(heap.getHeapId(), userVisibleText);
+    }
+
+    public void bindHeapDAO(HeapDAO heapDAO) {
+        this.heapDAO = heapDAO;
+    }
+
+    public void unbindHeapDAO(HeapDAO heapDAO) {
+        this.heapDAO = null;
+    }
+
+    public void bindVmInfoDAO(VmInfoDAO vmInfoDAO) {
+        this.vmInfoDAO = vmInfoDAO;
+    }
+
+    public void unbindVmInfoDAO(VmInfoDAO vmInfoDAO) {
+        this.vmInfoDAO = null;
+    }
+
+}
--- a/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java	Wed Dec 14 10:29:05 2016 -0500
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/ActivatorTest.java	Fri Dec 16 09:06:40 2016 -0500
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.vm.heap.analysis.command.internal;
 
-import com.redhat.thermostat.common.cli.CompleterService;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -48,7 +47,6 @@
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import static com.redhat.thermostat.testutils.Asserts.assertCommandIsRegistered;
-import static com.redhat.thermostat.testutils.Asserts.assertServiceIsRegistered;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
@@ -75,11 +73,10 @@
         assertCommandIsRegistered(ctx, "object-info", ObjectInfoCommand.class);
         assertCommandIsRegistered(ctx, "save-heap-dump-to-file", SaveHeapDumpToFileCommand.class);
         assertCommandIsRegistered(ctx, "show-heap-histogram", ShowHeapHistogramCommand.class);
-        assertServiceIsRegistered(ctx, CompleterService.class, HeapIdCompleterService.class);
-        
+
         activator.stop(ctx);
         
-        assertEquals(1, ctx.getAllServices().size()); // CompleterService remains
+        assertEquals(0, ctx.getAllServices().size());
     }
 
     private void makeConstructorsHappy(StubBundleContext ctx) {
--- a/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdCompleterServiceTest.java	Wed Dec 14 10:29:05 2016 -0500
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdCompleterServiceTest.java	Fri Dec 16 09:06:40 2016 -0500
@@ -38,8 +38,6 @@
 
 import com.redhat.thermostat.common.cli.CliCommandOption;
 import com.redhat.thermostat.common.cli.TabCompleter;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -58,20 +56,18 @@
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 public class HeapIdCompleterServiceTest {
 
-    private HeapDAO heapDao;
-    private VmInfoDAO vmInfoDao;
     private HeapIdCompleterService service;
+    private HeapIdsFinder heapIdsFinder;
 
     @Before
     public void setup() {
-        heapDao = mock(HeapDAO.class);
-        vmInfoDao = mock(VmInfoDAO.class);
+        heapIdsFinder = mock(HeapIdsFinder.class);
         service = new HeapIdCompleterService();
-        service.setHeapDAO(heapDao);
-        service.setVmInfoDAO(vmInfoDao);
+        service.bindHeapIdsFinder(heapIdsFinder);
     }
 
     @Test
@@ -101,9 +97,19 @@
             assertThat(opt.isRequired(), is(false));
             assertThat(opt.getDescription(), is(not(nullValue())));
             assertThat(opt.getDescription().length(), is(atLeast(1)));
+
+            TabCompleter tabCompleter = entry.getValue();
+            tabCompleter.complete("", 0, Collections.<CharSequence>emptyList());
+            verify(heapIdsFinder).findCompletions();
         }
     }
 
+    @Test
+    public void testGetSubcommandCompleters() {
+        assertThat(service.getSubcommandCompleters(),
+                is(equalTo(Collections.<String, Map<CliCommandOption, ? extends TabCompleter>>emptyMap())));
+    }
+
     private static Matcher<Integer> atLeast(final Integer i) {
         return new BaseMatcher<Integer>() {
             @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinderImplTest.java	Fri Dec 16 09:06:40 2016 -0500
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2012-2016 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.vm.heap.analysis.command.internal;
+
+import com.redhat.thermostat.common.Clock;
+import com.redhat.thermostat.common.cli.CompletionInfo;
+import com.redhat.thermostat.storage.core.VmId;
+import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.model.VmInfo;
+import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
+import com.redhat.thermostat.vm.heap.analysis.common.model.HeapInfo;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class HeapIdsFinderImplTest {
+
+    private HeapDAO heapDao;
+    private VmInfoDAO vmDao;
+    private HeapIdsFinderImpl finder;
+
+    @Before
+    public void setup() {
+        heapDao = mock(HeapDAO.class);
+        vmDao = mock(VmInfoDAO.class);
+
+        HeapInfo heapInfo1 = new HeapInfo();
+        heapInfo1.setTimeStamp(100L);
+        heapInfo1.setVmId("foo-vm");
+        heapInfo1.setAgentId("foo-agent");
+        heapInfo1.setHeapDumpId("foo-heapdump");
+        heapInfo1.setHistogramId("foo-histogram");
+        heapInfo1.setHeapId("foo-heap");
+
+        HeapInfo heapInfo2 = new HeapInfo();
+        heapInfo2.setTimeStamp(200L);
+        heapInfo2.setVmId("bar-vm");
+        heapInfo2.setAgentId("bar-agent");
+        heapInfo2.setHeapDumpId("bar-heapdump");
+        heapInfo2.setHistogramId("bar-histogram");
+        heapInfo2.setHeapId("bar-heap");
+
+        when(heapDao.getAllHeapInfo()).thenReturn(Arrays.asList(heapInfo1, heapInfo2));
+
+        VmInfo vmInfo1 = new VmInfo();
+        vmInfo1.setAgentId("foo-agent");
+        vmInfo1.setVmId("foo-vm");
+        vmInfo1.setMainClass("foo-mainclass");
+        vmInfo1.setStartTimeStamp(50L);
+        vmInfo1.setStopTimeStamp(-1L);
+
+        VmInfo vmInfo2 = new VmInfo();
+        vmInfo2.setAgentId("bar-agent");
+        vmInfo2.setVmId("bar-vm");
+        vmInfo2.setMainClass("bar-mainclass");
+        vmInfo2.setStartTimeStamp(75L);
+        vmInfo2.setStopTimeStamp(-1L);
+
+        when(vmDao.getVmInfo(new VmId("foo-vm"))).thenReturn(vmInfo1);
+        when(vmDao.getVmInfo(new VmId("bar-vm"))).thenReturn(vmInfo2);
+
+        finder = new HeapIdsFinderImpl();
+        finder.bindHeapDAO(heapDao);
+        finder.bindVmInfoDAO(vmDao);
+    }
+
+    @Test
+    public void testNumberOfResults() {
+        List<CompletionInfo> infos = finder.findCompletions();
+        assertThat(infos.size(), is(2));
+    }
+
+    @Test
+    public void testReturnsEmptyListWhenNoInfoFromDao() {
+        when(heapDao.getAllHeapInfo()).thenReturn(Collections.<HeapInfo>emptyList());
+        List<CompletionInfo> infos = finder.findCompletions();
+        assertThat(infos, is(equalTo(Collections.<CompletionInfo>emptyList())));
+    }
+
+    @Test
+    public void testResultFormat() {
+        List<CompletionInfo> infos = new ArrayList<>(finder.findCompletions());
+        Collections.sort(infos, new Comparator<CompletionInfo>() {
+            @Override
+            public int compare(CompletionInfo a, CompletionInfo b) {
+                return String.CASE_INSENSITIVE_ORDER.compare(a.getCompletionWithUserVisibleText(),
+                        b.getCompletionWithUserVisibleText());
+            }
+        });
+        CompletionInfo barInfo = infos.get(0);
+        CompletionInfo fooInfo = infos.get(1);
+
+        assertThat(barInfo.getActualCompletion(), is("bar-heap"));
+        assertThat(barInfo.getUserVisibleText(), is("bar-mainclass @ " + Clock.DEFAULT_DATE_FORMAT.format(new Date(200L))));
+
+        assertThat(fooInfo.getActualCompletion(), is("foo-heap"));
+        assertThat(fooInfo.getUserVisibleText(), is("foo-mainclass @ " + Clock.DEFAULT_DATE_FORMAT.format(new Date(100L))));
+    }
+
+    @Test
+    public void testReturnsEmptyWhenHeapDaoUnavailable() {
+        finder.unbindHeapDAO(heapDao);
+        assertThat(finder.findCompletions(), is(equalTo(Collections.<CompletionInfo>emptyList())));
+    }
+
+    @Test
+    public void testReturnsEmptyWhenVmDaoUnavailable() {
+        finder.unbindVmInfoDAO(vmDao);
+        assertThat(finder.findCompletions(), is(equalTo(Collections.<CompletionInfo>emptyList())));
+    }
+
+}
--- a/vm-heap-analysis/command/src/test/java/com/redhat/thermostat/vm/heap/analysis/command/internal/HeapIdsFinderTest.java	Wed Dec 14 10:29:05 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright 2012-2016 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.vm.heap.analysis.command.internal;
-
-import com.redhat.thermostat.common.Clock;
-import com.redhat.thermostat.common.cli.CompletionInfo;
-import com.redhat.thermostat.common.cli.DependencyServices;
-import com.redhat.thermostat.storage.core.VmId;
-import com.redhat.thermostat.storage.dao.VmInfoDAO;
-import com.redhat.thermostat.storage.model.VmInfo;
-import com.redhat.thermostat.vm.heap.analysis.common.HeapDAO;
-import com.redhat.thermostat.vm.heap.analysis.common.model.HeapInfo;
-import org.junit.Before;
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class HeapIdsFinderTest {
-
-    private BundleContext context;
-    private DependencyServices dependencyServices;
-    private HeapDAO heapDao;
-    private VmInfoDAO vmDao;
-    private HeapIdsFinder finder;
-
-    @Before
-    public void setup() {
-        context = mock(BundleContext.class);
-
-        dependencyServices = mock(DependencyServices.class);
-        heapDao = mock(HeapDAO.class);
-        vmDao = mock(VmInfoDAO.class);
-        when(dependencyServices.hasService(HeapDAO.class)).thenReturn(true);
-        when(dependencyServices.getService(HeapDAO.class)).thenReturn(heapDao);
-        when(dependencyServices.hasService(VmInfoDAO.class)).thenReturn(true);
-        when(dependencyServices.getService(VmInfoDAO.class)).thenReturn(vmDao);
-
-        HeapInfo heapInfo1 = new HeapInfo();
-        heapInfo1.setTimeStamp(100L);
-        heapInfo1.setVmId("foo-vm");
-        heapInfo1.setAgentId("foo-agent");
-        heapInfo1.setHeapDumpId("foo-heapdump");
-        heapInfo1.setHistogramId("foo-histogram");
-        heapInfo1.setHeapId("foo-heap");
-
-        HeapInfo heapInfo2 = new HeapInfo();
-        heapInfo2.setTimeStamp(200L);
-        heapInfo2.setVmId("bar-vm");
-        heapInfo2.setAgentId("bar-agent");
-        heapInfo2.setHeapDumpId("bar-heapdump");
-        heapInfo2.setHistogramId("bar-histogram");
-        heapInfo2.setHeapId("bar-heap");
-
-        when(heapDao.getAllHeapInfo()).thenReturn(Arrays.asList(heapInfo1, heapInfo2));
-
-        VmInfo vmInfo1 = new VmInfo();
-        vmInfo1.setAgentId("foo-agent");
-        vmInfo1.setVmId("foo-vm");
-        vmInfo1.setMainClass("foo-mainclass");
-        vmInfo1.setStartTimeStamp(50L);
-        vmInfo1.setStopTimeStamp(-1L);
-
-        VmInfo vmInfo2 = new VmInfo();
-        vmInfo2.setAgentId("bar-agent");
-        vmInfo2.setVmId("bar-vm");
-        vmInfo2.setMainClass("bar-mainclass");
-        vmInfo2.setStartTimeStamp(75L);
-        vmInfo2.setStopTimeStamp(-1L);
-
-        when(vmDao.getVmInfo(new VmId("foo-vm"))).thenReturn(vmInfo1);
-        when(vmDao.getVmInfo(new VmId("bar-vm"))).thenReturn(vmInfo2);
-
-        finder = new HeapIdsFinder(dependencyServices);
-    }
-
-    @Test
-    public void testNumberOfResults() {
-        List<CompletionInfo> infos = finder.findCompletions();
-        assertThat(infos.size(), is(2));
-    }
-
-    @Test
-    public void testReturnsEmptyListWhenNoInfoFromDao() {
-        when(heapDao.getAllHeapInfo()).thenReturn(Collections.<HeapInfo>emptyList());
-        List<CompletionInfo> infos = finder.findCompletions();
-        assertThat(infos, is(equalTo(Collections.<CompletionInfo>emptyList())));
-    }
-
-    @Test
-    public void testResultFormat() {
-        List<CompletionInfo> infos = new ArrayList<>(finder.findCompletions());
-        Collections.sort(infos, new Comparator<CompletionInfo>() {
-            @Override
-            public int compare(CompletionInfo a, CompletionInfo b) {
-                return String.CASE_INSENSITIVE_ORDER.compare(a.getCompletionWithUserVisibleText(),
-                        b.getCompletionWithUserVisibleText());
-            }
-        });
-        CompletionInfo barInfo = infos.get(0);
-        CompletionInfo fooInfo = infos.get(1);
-
-        assertThat(barInfo.getActualCompletion(), is("bar-heap"));
-        assertThat(barInfo.getUserVisibleText(), is("bar-mainclass @ " + Clock.DEFAULT_DATE_FORMAT.format(new Date(200L))));
-
-        assertThat(fooInfo.getActualCompletion(), is("foo-heap"));
-        assertThat(fooInfo.getUserVisibleText(), is("foo-mainclass @ " + Clock.DEFAULT_DATE_FORMAT.format(new Date(100L))));
-    }
-
-    @Test
-    public void testListDependencies() {
-        assertThat(finder.getRequiredDependencies(), is(equalTo(new Class[]{HeapDAO.class, VmInfoDAO.class})));
-    }
-
-}