changeset 1001:a51dd3bfa1d1

Merge
author Roman Kennke <rkennke@redhat.com>
date Tue, 26 Feb 2013 15:24:07 +0100
parents db242eb1da34 (current diff) 121a6919baf5 (diff)
children 81508fc5f27b
files
diffstat 8 files changed, 194 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java	Tue Feb 26 15:24:07 2013 +0100
@@ -114,12 +114,9 @@
                 bundlePaths = new LinkedList<>();
             }
 
-            for (String bundle : pluginBundles) {
-                bundlePaths.add(new File(pluginDir, bundle).toURI().toString());
-            }
-            for (String bundle : dependencyBundles) {
-                bundlePaths.add(new File(coreJarRoot, bundle).toURI().toString());
-            }
+            addIfValidPath(bundlePaths, pluginDir, pluginBundles);
+
+            addIfValidPath(bundlePaths, coreJarRoot, dependencyBundles);
 
             additionalBundlesForExistingCommands.put(commandName, bundlePaths);
         }
@@ -134,12 +131,10 @@
 
             List<String> bundlePaths = new LinkedList<>();
 
-            for (String bundle : command.getPluginBundles()) {
-                bundlePaths.add(new File(pluginDir, bundle).toURI().toString());
-            }
-            for (String bundle : command.getDepenedencyBundles()) {
-                bundlePaths.add(new File(coreJarRoot, bundle).toURI().toString());
-            }
+            addIfValidPath(bundlePaths, pluginDir, command.getPluginBundles());
+
+            addIfValidPath(bundlePaths, coreJarRoot, command.getDepenedencyBundles());
+
             BasicCommandInfo info = new BasicCommandInfo(commandName,
                     command.getDescription(),
                     command.getUsage(),
@@ -151,6 +146,17 @@
 
     }
 
+    private void addIfValidPath(List<String> result, File parentDir, List<String> pathsRelativeToParent) {
+        for (String bundle : pathsRelativeToParent) {
+            File bundleFile = new File(parentDir, bundle);
+            if (bundleFile.isFile()) {
+                result.add(bundleFile.toURI().toString());
+            } else {
+                logger.warning("File " + bundleFile.toString() + " not found. Removing it from list of bundles to load.");
+            }
+        }
+    }
+
     private void combineCommands() {
         Iterator<Entry<String, List<String>>> iter = additionalBundlesForExistingCommands.entrySet().iterator();
         while (iter.hasNext()) {
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java	Tue Feb 26 15:24:07 2013 +0100
@@ -55,7 +55,9 @@
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.xml.sax.ErrorHandler;
 import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
 
 import com.redhat.thermostat.common.Pair;
 import com.redhat.thermostat.common.utils.LoggingUtils;
@@ -113,6 +115,7 @@
         try {
             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
             DocumentBuilder builder = factory.newDocumentBuilder();
+            builder.setErrorHandler(new ConfigurationParserErrorHandler());
             Document xmlDoc = builder.parse(configurationStream);
             Node rootNode = xmlDoc.getFirstChild();
             if (rootNode == null) {
@@ -255,4 +258,21 @@
         return new Options();
     }
 
+    private static class ConfigurationParserErrorHandler implements ErrorHandler {
+
+        @Override
+        public void warning(SAXParseException exception) throws SAXException {
+            // no-op
+        }
+
+        @Override
+        public void fatalError(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+
+        @Override
+        public void error(SAXParseException exception) throws SAXException {
+            throw exception;
+        }
+    }
 }
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java	Tue Feb 26 15:24:07 2013 +0100
@@ -46,10 +46,17 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
 import java.util.List;
 
 import org.apache.commons.cli.Options;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
@@ -61,34 +68,56 @@
 
 public class PluginCommandInfoSourceTest {
 
-    // name paths so anything tying to use them/create them will blow up
-    private static final String PLUGIN_ROOT = "/fake/${PLUGIN_ROOT}";
-    private static final String JAR_ROOT = "/fake/${JAR_ROOT}";
-
-    private File jarRootDir;
-    private File pluginRootDir;
+    private Path testRoot;
+    private Path jarRootDir;
+    private Path pluginRootDir;
     private PluginConfigurationParser parser;
     private PluginConfiguration parserResult;
 
     @Before
-    public void setUp() throws FileNotFoundException {
+    public void setUp() throws IOException {
         parser = mock(PluginConfigurationParser.class);
         parserResult = mock(PluginConfiguration.class);
         when(parser.parse(isA(File.class))).thenReturn(parserResult);
-        pluginRootDir = mock(File.class);
-        jarRootDir = new File(JAR_ROOT);
+
+        testRoot = Files.createTempDirectory("thermostat");
+        pluginRootDir = testRoot.resolve("plugins");
+        Files.createDirectory(pluginRootDir);
+        jarRootDir = testRoot.resolve("libs");
+        Files.createDirectories(jarRootDir);
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        Files.walkFileTree(testRoot, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                if (exc == null) {
+                    Files.delete(dir);
+                    return FileVisitResult.CONTINUE;
+                } else {
+                    throw exc;
+                }
+            }
+        });
     }
 
     @Test
-    public void verifyParserIsInvokedOnAllConfigurationFiles() throws FileNotFoundException {
-        File[] pluginDirs = new File[] {
-                new File(PLUGIN_ROOT, "plugin1"),
-                new File(PLUGIN_ROOT, "plugin2"),
+    public void verifyParserIsInvokedOnAllConfigurationFiles() throws IOException {
+        Path[] pluginDirs = new Path[] {
+                pluginRootDir.resolve("plugin1"),
+                pluginRootDir.resolve("plugin2"),
         };
+        for (Path pluginDir : pluginDirs) {
+            Files.createDirectory(pluginDir);
+        }
 
-        when(pluginRootDir.listFiles()).thenReturn(pluginDirs);
-
-        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser);
+        new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser);
 
         ArgumentCaptor<File> configFilesCaptor = ArgumentCaptor.forClass(File.class);
         verify(parser, times(pluginDirs.length)).parse(configFilesCaptor.capture());
@@ -96,53 +125,58 @@
         List<File> configurationFiles = configFilesCaptor.getAllValues();
         assertEquals(pluginDirs.length, configurationFiles.size());
         for (int i = 0; i < pluginDirs.length; i++) {
-            assertEquals(new File(pluginDirs[i], "plugin.xml"), configurationFiles.get(i));
+            assertTrue(configurationFiles.contains(pluginDirs[i].resolve("plugin.xml").toFile()));
         }
     }
 
     @Test
     public void verifyMissingConfigurationFileIsHandledCorrectly() throws FileNotFoundException {
-        File[] pluginDirs = new File[] { new File(PLUGIN_ROOT, "plugin1") };
-
-        when(pluginRootDir.listFiles()).thenReturn(pluginDirs);
         when(parser.parse(isA(File.class))).thenThrow(new FileNotFoundException("test"));
 
-        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser);
+        new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser);
     }
 
     @Test(expected = CommandInfoNotFoundException.class)
     public void verifyMissingCommandInfo() {
-        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser);
+        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser);
 
         source.getCommandInfo("TEST");
     }
 
     @Test
-    public void verifyCommandInfoObjectsToExtendExistingCommandsAreCreated() {
+    public void verifyCommandInfoObjectsToExtendExistingCommandsAreCreated() throws IOException {
+        final String DEPENDENCY_BUNDLE = "dependency-bundle";
+        final String PLUGIN_BUNDLE = "plugin-bundle";
+
+        Path pluginDir = pluginRootDir.resolve("plugin1");
+        Files.createDirectory(pluginDir);
+        Path pluginJar = pluginDir.resolve(PLUGIN_BUNDLE);
+        Files.createFile(pluginJar);
+
+        Path dependencyJar = jarRootDir.resolve(DEPENDENCY_BUNDLE);
+        Files.createFile(dependencyJar);
+
         CommandExtensions extensions = mock(CommandExtensions.class);
         when(extensions.getCommandName()).thenReturn("command-name");
-        when(extensions.getPluginBundles()).thenReturn(Arrays.asList("additional-bundle"));
-        when(extensions.getDepenedencyBundles()).thenReturn(Arrays.asList("dependency-bundle"));
+        when(extensions.getPluginBundles()).thenReturn(Arrays.asList(PLUGIN_BUNDLE));
+        when(extensions.getDepenedencyBundles()).thenReturn(Arrays.asList(DEPENDENCY_BUNDLE));
 
         when(parserResult.getExtendedCommands()).thenReturn(Arrays.asList(extensions));
 
-        File[] pluginDirs = new File[] { new File(PLUGIN_ROOT, "plugin1") };
-        when(pluginRootDir.listFiles()).thenReturn(pluginDirs);
-
-        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser);
+        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser);
 
         CommandInfo info = source.getCommandInfo("command-name");
         assertEquals("command-name", info.getName());
 
-        String expectedDep1Name = new File(PLUGIN_ROOT + "/plugin1/additional-bundle").toURI().toString();
-        String expectedDep2Name = new File(JAR_ROOT + "/dependency-bundle").toURI().toString();
+        String expectedDep1Name = pluginJar.toFile().toURI().toString();
+        String expectedDep2Name = dependencyJar.toFile().toURI().toString();
 
         assertTrue(info.getDependencyResourceNames().contains(expectedDep1Name));
         assertTrue(info.getDependencyResourceNames().contains(expectedDep2Name));
     }
 
     @Test
-    public void verifyCommandInfoObjectsForNewComamndsAreCreated() {
+    public void verifyCommandInfoObjectsForNewComamndsAreCreated() throws IOException {
         final String NAME = "command-name";
         final String DESCRIPTION = "description of the command";
         final String USAGE = "usage";
@@ -150,6 +184,14 @@
         final String PLUGIN_BUNDLE = "plugin-bundle.jar";
         final String DEPENDENCY_BUNDLE = "dependency-bundle.jar";
 
+        Path pluginDir = pluginRootDir.resolve("plugin1");
+        Files.createDirectory(pluginDir);
+        Path pluginJar = pluginDir.resolve(PLUGIN_BUNDLE);
+        Files.createFile(pluginJar);
+
+        Path dependencyJar = jarRootDir.resolve(DEPENDENCY_BUNDLE);
+        Files.createFile(dependencyJar);
+
         NewCommand cmd = mock(NewCommand.class);
         when(cmd.getCommandName()).thenReturn(NAME);
         when(cmd.getDescription()).thenReturn(DESCRIPTION);
@@ -160,10 +202,7 @@
 
         when(parserResult.getNewCommands()).thenReturn(Arrays.asList(cmd));
 
-        File[] pluginDirs = new File[] { new File(PLUGIN_ROOT, "plugin1") };
-        when(pluginRootDir.listFiles()).thenReturn(pluginDirs);
-
-        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir, pluginRootDir, parser);
+        PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser);
 
         CommandInfo result = source.getCommandInfo(NAME);
 
@@ -172,8 +211,8 @@
         assertEquals(USAGE, result.getUsage());
         assertEquals(OPTIONS, result.getOptions());
 
-        String expectedDep1Name = new File(PLUGIN_ROOT + "/plugin1/" + PLUGIN_BUNDLE).toURI().toString();
-        String expectedDep2Name = new File(JAR_ROOT + "/" + DEPENDENCY_BUNDLE).toURI().toString();
+        String expectedDep1Name = pluginJar.toFile().toURI().toString();
+        String expectedDep2Name = dependencyJar.toFile().toURI().toString();
 
         List<String> deps = result.getDependencyResourceNames();
         assertEquals(2, deps.size());
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/DbServiceImpl.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/DbServiceImpl.java	Tue Feb 26 15:24:07 2013 +0100
@@ -64,16 +64,17 @@
     
     DbServiceImpl(String username, String password, String dbUrl) throws StorageException {
         BundleContext context = FrameworkUtil.getBundle(DbService.class).getBundleContext();
-        Storage storage = createStorage(context, username, password, dbUrl);
-        init(context, storage, dbUrl);
+        init(context, username, password, dbUrl);
     }
 
     // for testing
-    DbServiceImpl(BundleContext context, Storage storage, String dbUrl) {
-        init(context, storage, dbUrl);
+    DbServiceImpl(BundleContext context, String username, String password, String dbUrl) {
+        init(context, username, password, dbUrl);
     }
     
-    private void init(BundleContext context, Storage storage, String dbUrl) {
+    private void init(BundleContext context, String username, String password, String dbUrl) {
+        Storage storage = createStorage(context, username, password, dbUrl);
+
         this.storage = storage;
         this.context = context;
         this.dbUrl = dbUrl;
@@ -162,6 +163,9 @@
     private static StorageProvider getStorageProvider(BundleContext context, StartupConfiguration config) {
         try {
             ServiceReference[] refs = context.getServiceReferences(StorageProvider.class.getName(), null);
+            if (refs == null) {
+                throw new StorageException("No storage provider available");
+            }
             for (int i = 0; i < refs.length; i++) {
                 StorageProvider prov = (StorageProvider) context.getService(refs[i]);
                 prov.setConfig(config);
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/DbServiceImplTest.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/DbServiceImplTest.java	Tue Feb 26 15:24:07 2013 +0100
@@ -45,7 +45,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.osgi.framework.ServiceReference;
@@ -55,13 +54,15 @@
 import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
 import com.redhat.thermostat.storage.core.DbService;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.StorageException;
+import com.redhat.thermostat.storage.core.StorageProvider;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
 public class DbServiceImplTest {
     
     private Connection connection;
+    private StorageProvider storageProvider;
     private Storage storage;
-    private DbService dbService;
     private StubBundleContext context;
     
     @Before
@@ -72,17 +73,40 @@
         storage = mock(Storage.class);
         when(storage.getConnection()).thenReturn(connection);
 
-        dbService = new DbServiceImpl(context, storage, "http://someUrl.ignored.com");
+        storageProvider = mock(StorageProvider.class);
+        when(storageProvider.canHandleProtocol()).thenReturn(true);
+        when(storageProvider.createStorage()).thenReturn(storage);
+        context.registerService(StorageProvider.class, storageProvider, null);
     }
-    
-    @After
-    public void teardown() {
-        dbService = null;
-        context = null;
+
+    @Test
+    public void testNoStorageProvider() {
+        context = new StubBundleContext();
+
+        try {
+            new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+            fail("exception expected");
+        } catch (StorageException se) {
+            assertEquals("No storage provider available", se.getMessage());
+        }
+    }
+
+    @Test
+    public void testNoStorageProviderCanHandleStorageUrl() {
+        when(storageProvider.canHandleProtocol()).thenReturn(false);
+
+        try {
+            new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+            fail("exception expected");
+        } catch (StorageException se) {
+            assertEquals("No storage found for URL http://ignored.example.com", se.getMessage());
+        }
     }
 
     @Test
     public void testConnect() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.connect();
 
         verify(connection).connect();
@@ -90,6 +114,8 @@
     
     @Test
     public void testConnectRegistersDbService() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.connect();
 
         verify(connection).connect();
@@ -103,6 +129,8 @@
     
     @Test
     public void testConnectRegistersStorage() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.connect();
 
         verify(connection).connect();
@@ -117,6 +145,8 @@
     @SuppressWarnings("rawtypes")
     @Test
     public void testConnectEnforcesPreCond() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         ServiceRegistration reg = context.registerService(DbService.class, dbService, null);
         try {
             dbService.connect();
@@ -138,6 +168,8 @@
     @SuppressWarnings("rawtypes")
     @Test
     public void testDisConnectEnforcesPreCond() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         ServiceRegistration reg = context.registerService(DbService.class, dbService, null);
         try {
             // Storage == null
@@ -160,6 +192,8 @@
 
     @Test
     public void testDisconnect() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.connect();
         assertNotNull(context.getServiceReference(DbService.class));
         
@@ -170,6 +204,8 @@
 
     @Test
     public void testDisconnectUnregistersDbService() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.connect();
         assertNotNull(context.getServiceReference(DbService.class));
         
@@ -182,6 +218,8 @@
     
     @Test
     public void testDisconnectUnregistersStorage() {
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.connect();
         assertNotNull(context.getServiceReference(Storage.class));
         
@@ -196,13 +234,15 @@
     public void canGetStorageUrl() {
         String connectionURL = "http://test.example.com:8082";
 
-        dbService = new DbServiceImpl(context, null, connectionURL);
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", connectionURL);
         assertEquals(connectionURL, dbService.getConnectionUrl());
     }
     
     @Test
     public void testAddListener() {
         ConnectionListener listener = mock(ConnectionListener.class);
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
+
         dbService.addConnectionListener(listener);
         verify(connection).addListener(listener);
     }
@@ -211,6 +251,7 @@
     public void testRemoveListener() {
         // Remove called regardless of listener actually being added
         ConnectionListener listener = mock(ConnectionListener.class);
+        DbService dbService = new DbServiceImpl(context, "ignore", "ignore", "http://ignored.example.com");
         dbService.removeConnectionListener(listener);
         verify(connection).removeListener(listener);
     }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Tue Feb 26 15:24:07 2013 +0100
@@ -47,6 +47,7 @@
 import sun.jvmstat.monitor.MonitoredHost;
 
 import com.redhat.thermostat.backend.BaseBackend;
+import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
@@ -72,11 +73,12 @@
     private final HostInfoBuilder hostInfoBuilder;
 
 
-    public SystemBackend(HostInfoDAO hostInfoDAO, NetworkInterfaceInfoDAO netInfoDAO, VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier) {
+    public SystemBackend(HostInfoDAO hostInfoDAO, NetworkInterfaceInfoDAO netInfoDAO, VmInfoDAO vmInfoDAO,
+            Version version, VmStatusChangeNotifier notifier) {
         super("System Backend",
                 "Gathers basic information from the system",
                 "Red Hat, Inc.",
-                "0.5.0", true);
+                version.getVersionNumber(), true);
         this.hostInfos = hostInfoDAO;
         this.networkInterfaces = netInfoDAO;
 
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Tue Feb 26 15:24:07 2013 +0100
@@ -48,6 +48,7 @@
 import com.redhat.thermostat.backend.system.VmStatusChangeNotifier;
 import com.redhat.thermostat.common.MultipleServiceTracker;
 import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
@@ -79,7 +80,8 @@
                 NetworkInterfaceInfoDAO netInfoDAO = (NetworkInterfaceInfoDAO) services
                         .get(NetworkInterfaceInfoDAO.class.getName());
                 VmInfoDAO vmInfoDAO = (VmInfoDAO) services.get(VmInfoDAO.class.getName());
-                backend = new SystemBackend(hostInfoDAO, netInfoDAO, vmInfoDAO, notifier);
+                Version version = new Version(context.getBundle());
+                backend = new SystemBackend(hostInfoDAO, netInfoDAO, vmInfoDAO, version, notifier);
                 reg = context.registerService(Backend.class, backend, null);
             }
             
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Tue Feb 26 14:56:40 2013 +0100
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Tue Feb 26 15:24:07 2013 +0100
@@ -36,19 +36,23 @@
 
 package com.redhat.thermostat.backend.system;
 
+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 org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 
 public class SystemBackendTest {
 
+    private static final String VERSION = "0.0.0";
     private SystemBackend b;
 
     @Before
@@ -57,9 +61,12 @@
         NetworkInterfaceInfoDAO nDAO = mock(NetworkInterfaceInfoDAO.class);
         VmInfoDAO vmInfoDAO = mock(VmInfoDAO.class);
 
+        Version version = mock(Version.class);
+        when(version.getVersionNumber()).thenReturn(VERSION);
+        
         VmStatusChangeNotifier notifier = mock(VmStatusChangeNotifier.class);
 
-        b = new SystemBackend(hDAO, nDAO, vmInfoDAO, notifier);
+        b = new SystemBackend(hDAO, nDAO, vmInfoDAO, version, notifier);
     }
 
     @Test
@@ -84,6 +91,11 @@
         b.deactivate();
         assertFalse(b.isActive());
     }
+    
+    @Test
+    public void testVersion() {
+        assertEquals(VERSION, b.getVersion());
+    }
 
 }