changeset 1708:4cf9650b8bb1

Merge.
author Jon VanAlten <jon.vanalten@redhat.com>
date Tue, 23 Jun 2015 09:57:32 -0600
parents 911fc6601c4d (current diff) 512f81ecb539 (diff)
children 0f4eb944e00b
files common/pom.xml dev/perflog-analyzer/pom.xml distribution/config/commands/add-mongodb-user.properties pom.xml storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommand.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandDispatcher.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/BaseAddUserCommand.java storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/StartStopAddUserCommandDecorator.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandDispatcherTest.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandTest.java storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/BaseAddUserCommandTest.java vm-profiler/jvm-agent/pom.xml
diffstat 74 files changed, 839 insertions(+), 1277 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/annotations/src/main/java/com/redhat/thermostat/annotations/internal/CacioTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2015 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.annotations.internal;
+
+/**
+ * Temporary workaround for PR2282: Caciocavallo tests fail with JDK 8 u40
+ * Use this annotation on test classes to exclude them from being run by the maven-surefire-plugin
+ */
+public interface CacioTest {
+}
--- a/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/host/swing/DeadHostIconDecoratorTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/host/swing/DeadHostIconDecoratorTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -43,13 +43,16 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.UIDefaults;
 import com.redhat.thermostat.client.ui.PlatformIcon;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 
+@Category(CacioTest.class)
 public class DeadHostIconDecoratorTest {
 
     private DeadHostIconDecorator decorator;
--- a/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/host/swing/HostIconDecoratorTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/host/swing/HostIconDecoratorTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -45,12 +45,15 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.UIDefaults;
 import com.redhat.thermostat.client.ui.PlatformIcon;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.VmRef;
 
+@Category(CacioTest.class)
 public class HostIconDecoratorTest {
 
     private HostIconDecorator decorator;
--- a/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -41,9 +41,10 @@
 import static org.mockito.Mockito.when;
 
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.filter.host.swing.DeadHostIconDecorator;
-import com.redhat.thermostat.client.filter.host.swing.HostIconDecorator;
 import com.redhat.thermostat.client.filter.host.swing.HostInfoLabelDecorator;
 import com.redhat.thermostat.client.swing.UIDefaults;
 import com.redhat.thermostat.client.ui.ReferenceFieldIconDecorator;
@@ -53,6 +54,7 @@
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.testutils.StubBundleContext;
 
+@Category(CacioTest.class)
 public class VMFilterActivatorTest {
     
     @Test
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/MenuHelperTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/MenuHelperTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -63,9 +63,11 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.ui.MenuAction;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class MenuHelperTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/ActionButtonTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/ActionButtonTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -57,10 +57,13 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class ActionButtonTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/FontAwesomeIconTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/FontAwesomeIconTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -43,7 +43,11 @@
 import java.awt.image.BufferedImage;
 
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
+
+@Category(CacioTest.class)
 public class FontAwesomeIconTest {
 
     @Test
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/HeaderPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/HeaderPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -57,14 +57,17 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertEquals;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class HeaderPanelTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/RecentTimeSeriesChartPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/RecentTimeSeriesChartPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -41,6 +41,7 @@
 import java.util.concurrent.TimeUnit;
 import javax.swing.JFrame;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController;
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 import org.fest.swing.annotation.GUITest;
@@ -55,8 +56,10 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class RecentTimeSeriesChartPanelTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/SearchFieldTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/SearchFieldTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -62,11 +62,12 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
-import com.redhat.thermostat.client.swing.components.SearchField;
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class SearchFieldTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/RecentTimeControlPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/RecentTimeControlPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -46,6 +46,7 @@
 import javax.swing.JFrame;
 import javax.swing.JComboBox;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.experimental.Duration;
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 import org.fest.swing.annotation.GUITest;
@@ -58,8 +59,10 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class RecentTimeControlPanelTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/SingleValueChartPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/experimental/SingleValueChartPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -44,6 +44,7 @@
 import java.util.concurrent.TimeUnit;
 import javax.swing.JFrame;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.experimental.Duration;
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 import org.fest.swing.annotation.GUITest;
@@ -58,8 +59,10 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class SingleValueChartPanelTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/models/NullSelectionModelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/components/models/NullSelectionModelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -53,8 +53,12 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
+
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class NullSelectionModelTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/experimental/ComponentVisibilityNotifierTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/experimental/ComponentVisibilityNotifierTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -55,13 +55,13 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.client.core.views.BasicView.Action;
-import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier;
 import com.redhat.thermostat.common.ActionNotifier;
 
 @GUITest
-@Category(GUITest.class)
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class ComponentVisibilityNotifierTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/MainWindowTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -61,12 +61,14 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.client.ui.MenuAction;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class MainWindowTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/StatusBarTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/StatusBarTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -58,10 +58,13 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class StatusBarTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/AccordionTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -67,8 +67,10 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.components.EmptyIcon;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class AccordionTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/TitledPaneTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/accordion/TitledPaneTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -57,10 +57,13 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.components.VerticalLayout;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class TitledPaneTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/AgentInformationDisplayFrameTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/AgentInformationDisplayFrameTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -66,12 +66,13 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.AgentInformationDisplayView;
 import com.redhat.thermostat.client.core.views.AgentInformationDisplayView.ConfigurationAction;
-import com.redhat.thermostat.client.swing.internal.views.AgentInformationDisplayFrame;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class AgentInformationDisplayFrameTest {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/ClientConfigurationSwingTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/ClientConfigurationSwingTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -62,12 +62,13 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.ClientConfigurationView;
-import com.redhat.thermostat.client.swing.internal.views.ClientConfigurationSwing;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.test.Bug;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class ClientConfigurationSwingTest {
     
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/HostInformationPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/HostInformationPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -48,13 +48,16 @@
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiQuery;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.UIComponent;
 import com.redhat.thermostat.client.swing.FrameWithPanelTest;
 import com.redhat.thermostat.client.swing.TabbedPaneMatcher;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class HostInformationPanelTest extends FrameWithPanelTest<HostInformationPanel> {
 
--- a/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/VmInformationPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/client/swing/src/test/java/com/redhat/thermostat/client/swing/internal/views/VmInformationPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -43,12 +43,15 @@
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiQuery;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.UIComponent;
 import com.redhat.thermostat.client.swing.FrameWithPanelTest;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class VmInformationPanelTest extends FrameWithPanelTest<VmInformationPanel> {
 
--- a/common/pom.xml	Thu Jun 04 00:38:59 2015 -0500
+++ b/common/pom.xml	Tue Jun 23 09:57:32 2015 -0600
@@ -56,6 +56,12 @@
       <artifactId>junit</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <modules>
--- a/dev/perflog-analyzer/pom.xml	Thu Jun 04 00:38:59 2015 -0500
+++ b/dev/perflog-analyzer/pom.xml	Tue Jun 23 09:57:32 2015 -0600
@@ -62,6 +62,13 @@
       <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
+
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   
   <build>
--- a/distribution/config/commands/add-mongodb-user.properties	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-bundles = com.redhat.thermostat.storage.mongodb=${project.version}, \
-          org.mongodb.mongo-java-driver=${mongo-driver.osgi-version}, \
-          org.apache.commons.beanutils=${commons-beanutils.version}, \
-          org.apache.commons.codec=${commons-codec.osgi-version}, \
-          org.apache.commons.collections=${commons-collections.version}, \
-          org.apache.commons.logging=${commons-logging.version}
-
-summary = add a new mongodb user to the thermostat DB
-
-description = Add a new mongodb user to the thermostat DB, reading credentials \
- from standard input.
-
-usage = add-mongodb-user -d <dbUrl> |\
-        add-mongodb-user -s
-
-options = AUTO_LOG_OPTION, AUTO_DB_OPTIONS, startStorage
-
-startStorage.short = s
-startStorage.long = startStorage
-startStorage.description = start storage with appropriate options before \
- running the command and stop the storage when the command finishes
-startStorage.required = false
-startStorage.hasarg = false
-
-environments = cli
--- a/distribution/scripts/thermostat-devsetup	Thu Jun 04 00:38:59 2015 -0500
+++ b/distribution/scripts/thermostat-devsetup	Tue Jun 23 09:57:32 2015 -0600
@@ -54,10 +54,11 @@
 
 # Call the setup script
 $THERMOSTAT_SETUP < $DEV_INPUT
+retval=$?
 
-if [ $? -ne 0 ]; then
+if [ $retval -ne 0 ]; then
   echo "Development setup failed." 1>&2
-  exit $?
+  exit $retval
 fi
 
 # Copy the agent.auth file into USER_THERMOSTAT_HOME
--- a/distribution/scripts/thermostat-setup	Thu Jun 04 00:38:59 2015 -0500
+++ b/distribution/scripts/thermostat-setup	Tue Jun 23 09:57:32 2015 -0600
@@ -270,15 +270,43 @@
   echo -e "connections.\n"
   readUsername "$defaultName"
   readPassword
-  setupCmdName="add-mongodb-user -s"
-  output="$(echo -e $USERNAME\\n$PASSWORD\\n | $THERMOSTAT $setupCmdName 2>&1)"
-  # The above should have created the mongodb stamp file
-  monogdbSetupStampFile="$USER_THERMOSTAT_HOME/data/mongodb-user-done.stamp"
-  if [ ! -e "$monogdbSetupStampFile" ] ||
-    ! echo $output | grep -s "setup complete" > /dev/null; then
+  $THERMOSTAT_HOME/bin/thermostat storage --start --permitLocalhostException
+  MONGOD_RETVAL="$?"
+  if [ "$MONGOD_RETVAL" -ne 0 ] ; then
+    echo -e "\nMongodb user setup failed. Error starting storage." 1>&2
+    exitFail
+  fi
+  sleep 3
+  mongo 127.0.0.1:27518 << EOF
+use thermostat
+var v = db.version();
+var minorMicro = v.substr(v.indexOf('.') + 1)
+var minorVersion = minorMicro.substr(0, minorMicro.indexOf('.'))
+if ( minorVersion <= 2 ) {
+    // mongodb version 2.2 and below don't have the third argument.
+    // this should create the user as read + write.
+    db.addUser("$USERNAME","$PASSWORD")
+} else {
+  if ( minorVersion <= 4 ) {
+    db.addUser({ user: "$USERNAME", pwd: "$PASSWORD", roles: [ "readWrite" ] })
+  } else {
+    db.createUser({ user: "$USERNAME", pwd: "$PASSWORD", roles: [ "readWrite" ] })
+  }
+}
+quit()
+EOF
+  MONGO_SETUP_RETVAL="$?"
+  if [ "$MONGO_SETUP_RETVAL" -ne 0 ] ; then
     echo -e "\nMongodb user setup failed." 1>&2
     exitFail
   fi
+  $THERMOSTAT_HOME/bin/thermostat storage --stop
+  MONGO_SETUP_RETVAL="$?"
+  if [ "$MONGO_SETUP_RETVAL" -ne 0 ] ; then
+    echo -e "\nMongodb user setup failed." 1>&2
+    exitFail
+  fi
+  touch "$USER_THERMOSTAT_HOME"/data/mongodb-user-done.stamp
 }
 
 doProceedLoop() {
--- a/distribution/tools/verify-archetype-functions.sh	Thu Jun 04 00:38:59 2015 -0500
+++ b/distribution/tools/verify-archetype-functions.sh	Tue Jun 23 09:57:32 2015 -0600
@@ -77,7 +77,7 @@
   if [ "x$KEEPTEMP" != "x--keepTemp" ]; then
     cleanup_tempdirs $TMP_DIR \
           $PLUGIN_INSTALL_LOCATION \
-          $THERMOSTAT_HOME/webapp/WEB-INF/lib/"$ARTIFACT_ID"-storage-common-0.0.1-SNAPSHOT.jar
+          $THERMOSTAT_HOME/webapp/WEB-INF/lib/"$ARTIFACT_ID"-storage-common*.jar
   fi
 }
 
@@ -96,13 +96,32 @@
 }
 
 function exit_if_bad_return_value() {
-  RVAL=$1
-  if [ $RVAL -ne 0 ]; then
+  local rval=""
+  local debugFile=""
+  local errorMsg=""
+
+  # Check if we got passed a third argument which is a file with
+  # details about the failure that happened.
+  if [ $# -eq 3 ]; then
+    rval=$1
+    debugFile=$2
+    errorMsg=$3
+  else
+    rval=$1
+    debugFile=""
+    errorMsg=$2
+  fi
+
+  if [ $rval -ne 0 ]; then
+    # Only print debug info if we actually have one
+    if [ "_$debugFile" != "_" ]; then
+      echo "------------------- Debug info start ---------------------"
+      cat "$debugFile"
+      echo "-------------------  Debug info end  ---------------------"
+    fi
     cleanup
-    shift
-    echo $@
+    echo "$errorMsg"
     output_fail_information
-    exit $RVAL
+    exit $rval
   fi
 }
-
--- a/distribution/tools/verify-archetype-multimodule.sh	Thu Jun 04 00:38:59 2015 -0500
+++ b/distribution/tools/verify-archetype-multimodule.sh	Tue Jun 23 09:57:32 2015 -0600
@@ -53,6 +53,8 @@
 
 WSS_PID="$TMP_DIR/web-storage-service.pid"
 WSS_OUTPUT="$TMP_DIR/wss_output.txt"
+EXAMPLE_CMD_OUTPUT="$TMP_DIR/example_cmd_output.txt"
+
 
 function launch_and_wait_for_web_storage() {
   $THERMOSTAT_EXE -Tbg $WSS_PID web-storage-service > $WSS_OUTPUT 2>&1
@@ -124,7 +126,7 @@
 exit_if_bad_return_value $? "Error configuring Thermostat (devsetup)"
 
 launch_and_wait_for_web_storage
-exit_if_bad_return_value $? "Web Storage Service not coming up"
+exit_if_bad_return_value $? "$WSS_OUTPUT" "Web Storage Service not coming up"
 
 # Why head -n4? Output looks like the following:
 #
@@ -142,8 +144,10 @@
 exit_if_bad_return_value $? "Plugin command not appearing in Thermostat help"
 
 # verify "example-command" works as expected
-echo -e "client-tester\ntester" | $THERMOSTAT_EXE example-command -a $AGENT_ID | grep 'Message: Hello World!'
-exit_if_bad_return_value $? "Plugin command not working"
+example_cmd="echo -e \"client-tester\ntester\" | $THERMOSTAT_EXE example-command -a $AGENT_ID | grep 'Message: Hello World!'"
+echo $example_cmd >> $EXAMPLE_CMD_OUTPUT 2>&1
+$example_cmd >> $EXAMPLE_CMD_OUTPUT 2>&1
+exit_if_bad_return_value $? "$EXAMPLE_CMD_OUTPUT" "Plugin command not working"
 
 kill_and_wait_for_webstorage
 
--- a/host-memory/client-swing/src/main/java/com/redhat/thermostat/host/memory/client/swing/internal/HostMemoryPanel.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/host-memory/client-swing/src/main/java/com/redhat/thermostat/host/memory/client/swing/internal/HostMemoryPanel.java	Tue Jun 23 09:57:32 2015 -0600
@@ -58,6 +58,7 @@
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.NumberAxis;
 import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.data.RangeType;
 import org.jfree.data.time.FixedMillisecond;
 import org.jfree.data.time.RegularTimePeriod;
 import org.jfree.data.time.TimeSeries;
@@ -315,6 +316,7 @@
 
         NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
         rangeAxis.setAutoRangeMinimumSize(100);
+        rangeAxis.setRangeType(RangeType.POSITIVE);
 
         return chart;
     }
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -146,6 +146,21 @@
         }
     }
     
+    protected static void createFakeUserSetupDoneFile() {
+        String userHome = getUserThermostatHome();
+        File fUserHome = new File(userHome);
+        fUserHome.mkdir();
+        File dataDir = new File(fUserHome, "data");
+        dataDir.mkdir();
+
+        File mongodbUserDoneFile = new File(dataDir, "mongodb-user-done.stamp");
+        try {
+            // creates the file only if not yet existing
+            mongodbUserDoneFile.createNewFile();
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
 
     /**
      * Utility method for removing stamp files which may get created by certain
@@ -245,8 +260,6 @@
     }
     
     public static Spawn startStorage() throws Exception {
-        clearStorageDataDirectory();
-
         Spawn storage = spawnThermostat("storage", "--start", "--permitLocalhostException");
         try {
             storage.expect("pid:");
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -68,9 +68,9 @@
 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.StorageCredentials;
 import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.StorageCredentials;
 import com.redhat.thermostat.storage.mongodb.internal.MongoStorage;
 import com.redhat.thermostat.storage.query.Expression;
 import com.redhat.thermostat.storage.query.ExpressionFactory;
@@ -123,6 +123,7 @@
     @BeforeClass
     public static void setUpOnce() throws Exception {
         createFakeSetupCompleteFile();
+        clearStorageDataDirectory();
         startStorage();
 
         addCpuData(4);
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -51,6 +51,7 @@
 
     // @BeforeClass // reinstate once we actually need storage running (see ignored tests)
     public static void setUpOnce() throws Exception {
+        clearStorageDataDirectory();
         startStorage();
     }
 
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/StorageTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -59,8 +59,9 @@
 
     @Test
     public void startAndStopStorage() throws Exception {
+        clearStorageDataDirectory();
+
         Spawn storage;
-
         storage = startStorage();
 
         storage = spawnThermostat("storage", "--status");
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -54,6 +54,7 @@
     @BeforeClass
     public static void setUpOnce() throws Exception {
         createFakeSetupCompleteFile();
+        clearStorageDataDirectory();
         startStorage();
 
         // TODO insert actual data into the database and test that
--- a/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/integration-tests/itest-run/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -50,6 +50,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
@@ -60,10 +61,12 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Properties;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.jetty.server.Server;
@@ -101,6 +104,7 @@
 import com.redhat.thermostat.storage.model.AgentInformation;
 import com.redhat.thermostat.storage.model.AggregateCount;
 import com.redhat.thermostat.storage.model.HostInfo;
+import com.redhat.thermostat.storage.model.Pojo;
 import com.redhat.thermostat.storage.mongodb.internal.MongoStorage;
 import com.redhat.thermostat.storage.query.Expression;
 import com.redhat.thermostat.storage.query.ExpressionFactory;
@@ -113,6 +117,7 @@
 import com.redhat.thermostat.web.client.internal.WebStorage;
 import com.redhat.thermostat.web.server.auth.Roles;
 
+import expectj.ExpectJ;
 import expectj.Spawn;
 import expectj.TimeoutException;
 
@@ -237,11 +242,10 @@
 
     private static final String TEST_USER = "testuser";
     private static final String TEST_PASSWORD = "testpassword";
-    private static final String PREP_USER = "prepuser";
-    private static final String PREP_PASSWORD = "preppassword";
     private static final double EQUALS_DELTA = 0.00000000000001;
     private static final String THERMOSTAT_USERS_FILE = getConfigurationDir() + "/thermostat-users.properties";
     private static final String THERMOSTAT_ROLES_FILE = getConfigurationDir() + "/thermostat-roles.properties";
+    private static final String THERMOSTAT_WEB_AUTH_FILE = getConfigurationDir() + "/web.auth";
     private static final String VM_ID1 = "vmId1";
     private static final String VM_ID2 = "vmId2";
     private static final String VM_ID3 = "vmId3";
@@ -250,25 +254,41 @@
     private static int port;
     private static Path backupUsers;
     private static Path backupRoles;
+    private static Path backupWebAuth;
 
     @BeforeClass
     public static void setUpOnce() throws Exception {
-        
-        // This starts storage with the permit localhost exception option.
-        // It's important to start storage with that exception. Otherwise the
-        // mongodb user creds setup will fail.
-        createFakeSetupCompleteFile();
-        startStorage();
-        
-        setupMongodbUser();
+        clearStorageDataDirectory();
 
         backupUsers = Files.createTempFile("itest-backup-thermostat-users", "");
         backupRoles = Files.createTempFile("itest-backup-thermostat-roles", "");
+        backupWebAuth = Files.createTempFile("itest-backup-webapp-auth", "");
         backupRoles.toFile().deleteOnExit();
         backupUsers.toFile().deleteOnExit();
+        backupWebAuth.toFile().deleteOnExit();
         Files.copy(new File(THERMOSTAT_USERS_FILE).toPath(), backupUsers, StandardCopyOption.REPLACE_EXISTING);
         Files.copy(new File(THERMOSTAT_ROLES_FILE).toPath(), backupRoles, StandardCopyOption.REPLACE_EXISTING);
+        Files.copy(new File(THERMOSTAT_WEB_AUTH_FILE).toPath(), backupWebAuth, StandardCopyOption.REPLACE_EXISTING);
 
+        createFakeSetupCompleteFile();
+        createFakeUserSetupDoneFile();
+
+        setupMongodbUser();
+
+        startStorage();
+
+        ExpectJ mongo = new ExpectJ(TIMEOUT_IN_SECONDS);
+        Spawn mongoSpawn = mongo.spawn("mongo 127.0.0.1:27518");
+        mongoSpawn.send("use thermostat\n");
+        mongoSpawn.expect("switched to db thermostat");
+        mongoSpawn.send(String.format("db.auth(\"%s\", \"%s\")\n", getMongodbUsername(), getMongodbPassword()));
+        mongoSpawn.expect("1");
+        mongoSpawn.send("db[\"fake\"].insert({foo:\"bar\", baz: 1})\n");
+        mongoSpawn.send("db[\"fake\"].findOne()\n");
+        mongoSpawn.send("show collections\n");
+        mongoSpawn.send("show users\n");
+
+        createWebAuthFile();
 
         // start the server, deploy the war
         port = FreePortFinder.findFreePort(new TryPort() {
@@ -284,62 +304,121 @@
 
     @AfterClass
     public static void tearDownOnce() throws Exception {
-        deleteCpuData();
+        try {
+            deleteCpuData();
+        } catch (Exception e) {
+            System.out.println("AN ERROR OCCURRED DELETING CPU DATA!");
+            e.printStackTrace();
+            throw e;
+        } finally {
+            try {
+                server.stop();
+                server.join();
+            } catch (Exception e) {
+                System.out.println("AN ERROR OCCURRED STOPPING JETTY!");
+                e.printStackTrace();
+                throw e;
+            } finally {
+                try {
+                    stopStorage();
+                } catch (Exception e) {
+                    System.out.println("AN ERROR OCCURRED STOPPING STORAGE!");
+                    e.printStackTrace();
+                    throw e;
+                } finally {
+                    removeSetupCompleteStampFiles();
+                    Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
+                    Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
+                    Files.copy(backupWebAuth, new File(THERMOSTAT_WEB_AUTH_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
+                    System.out.println("RESTORED backed-up files!");
+                }
+            }
+        }
+    }
     
-        server.stop();
-        server.join();
-        
-        stopStorage();
-        removeSetupCompleteStampFiles();
-    
-        Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
-        Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
+    private static long countAllData(BackingStorage storage, Category<AggregateCount> cat) {
+        try {
+            String countAllDataDesc = "QUERY-COUNT " + cat.getName();
+            StatementDescriptor<AggregateCount> desc = new StatementDescriptor<>(cat, countAllDataDesc);
+            PreparedStatement<AggregateCount> statement = storage.prepareStatement(desc);
+            Cursor<AggregateCount> cursor = statement.executeQuery();
+            assert cursor.hasNext();
+            AggregateCount aggregate = cursor.next();
+            long count = aggregate.getCount();
+            return count;
+        } catch (StatementExecutionException | DescriptorParsingException e) {
+            throw new AssertionError(e);
+        }
     }
 
     // PRE: storage started with --permitLocalhostException
     private static void setupMongodbUser() throws Exception {
-        // The actual setup is only required for devel builds.
-        // Release builds won't have a web.xml with actual username/passwords
-        // in it, so starting backing storage (i.e. mongodb) with the 
-        // --permitLocalhostException option is sufficient.
-        if (isDevelopmentBuild()) {
-            
-            // Remove the mongodb-user-added.stamp file,
-            // but keep the main setup file around so as to be able to
-            // actually launch thermostat.
-            removeSetupCompleteStampFiles();
-            createFakeSetupCompleteFile();
+        String mongodbUsername = getMongodbUsername();
+        String mongodbPassword = getMongodbPassword();
+
+        final String HOST = "127.0.0.1";
+        final String PORT = "27518";
+
+        try {
+            System.out.println("THERMOSTAT_HOME: " + getThermostatHome());
+            System.out.println("USER_THERMOSTAT_HOME: " + getUserThermostatHome());
+
+            // start mongod
+            startStorage();
+
+            System.out.println("Started mongod");
+            TimeUnit.SECONDS.sleep(3);
+
+            ExpectJ mongo = new ExpectJ(TIMEOUT_IN_SECONDS);
+            Spawn mongoSpawn = mongo.spawn("mongo " + HOST + ":" + PORT);
+            mongoSpawn.send("use thermostat\n");
+            mongoSpawn.send("var v = db.version()\n");
+            mongoSpawn.send("var minorMicro = v.substr(v.indexOf('.') + 1)\n");
+            mongoSpawn.send("var minorVersion = minorMicro.substr(0, minorMicro.indexOf('.'))\n");
+            mongoSpawn.send("if ( minorVersion <= 2 ) {");
+            mongoSpawn.send(String.format("db.addUser(\"%s\", \"%s\")", mongodbUsername, mongodbPassword));
+            mongoSpawn.send("} else {");
+            mongoSpawn.send("if ( minorVersion <= 4 ) {");
+            mongoSpawn.send(String.format("db.addUser({ user: \"%s\", pwd: \"%s\", roles: [ \"readWrite\" ] })",
+                    mongodbUsername, mongodbPassword));
+            mongoSpawn.send("} else {");
+            mongoSpawn.send(String.format("db.createUser({ user: \"%s\", pwd: \"%s\", roles: [ \"readWrite\" ] })",
+                    mongodbUsername, mongodbPassword));
+            mongoSpawn.send("}\n");
+            mongoSpawn.send("}\n");
+            mongoSpawn.send("quit()\n");
+            mongoSpawn.expectClose();
+
+            mongo = new ExpectJ(TIMEOUT_IN_SECONDS);
+            mongoSpawn = mongo.spawn("mongo " + HOST + ":" + PORT);
+            mongoSpawn.send("use thermostat\n");
+            mongoSpawn.expect("switched to db thermostat");
+            mongoSpawn.send(String.format("db.auth(\"%s\", \"%s\")\n", mongodbUsername, mongodbPassword));
+            mongoSpawn.expect("1");
+
+            // now insert some fake data and display some information that
+            // might be useful for post-mortem analysis if this test fails
+            mongoSpawn.send("db[\"fake\"].insert({foo:\"bar\", baz: 1})\n");
+            mongoSpawn.send("db[\"fake\"].findOne()\n");
+            mongoSpawn.send("show collections\n");
+            mongoSpawn.send("show users\n");
             
-            String mongodbUsername = getMongodbUsername();
-            String mongodbPassword = getMongodbPassword();
-            String creds = String.format("%s\n%s\n", mongodbUsername,
-                                                     mongodbPassword);
-            String[] addUserArgs = new String[] {
-                    "add-mongodb-user",
-                    "-d", "mongodb://127.0.0.1:27518"
-            };
-            
-            // This should be an equivalent of:
-            // $ echo -e "mongodbUsername\nmongodbPassword\n" | \
-            //   thermostat add-mongodb-user -d mongodb://127.0.0.1:27518
-            Spawn addUser = spawnThermostat(addUserArgs);
-            addUser.send(creds);
-            try {
-                addUser.expect("mongodb user setup complete");
-            } catch (TimeoutException | IOException e) {
-                // failed to set up mongodb user, stop storage and bail.
-                stopStorage();
-                throw e;
-            }
-            addUser.expectClose();
-        } else {
-            System.out.println("Not a development build. Skipping mongodb setup.");
+        } catch (TimeoutException | IOException e) {
+            throw e;
+        } finally {
+            stopStorage();
         }
     }
 
+    private static void createWebAuthFile() throws IOException {
+        System.out.println("WRITING auth file: " + getMongodbUsername() + "/" + getMongodbPassword());
+        List<String> lines = new ArrayList<String>();
+        lines.add("storage.username = " + getMongodbUsername());
+        lines.add("storage.password = " + getMongodbPassword());
+        Files.write(new File(THERMOSTAT_WEB_AUTH_FILE).toPath(), lines, StandardCharsets.UTF_8);
+    }
+
     private static String getMongodbUsername() {
-        assertTrue(isDevelopmentBuild());
-        
         // Define this default in order for IDE based runs to require fewer
         // properties to be set.
         String defaultDevUser = "mongodevuser";
@@ -348,8 +427,6 @@
     }
 
     private static String getMongodbPassword() {
-        assertTrue(isDevelopmentBuild());
-        
         // Define this default in order for IDE based runs to require fewer
         // properties to be set.
         String defaultDevPassword = "mongodevpassword";
@@ -368,12 +445,12 @@
 
             @Override
             public String getUsername() {
-                return null;
+                return getMongodbUsername();
             }
 
             @Override
             public char[] getPassword() {
-                return null;
+                return getMongodbPassword().toCharArray();
             }
             
         };
@@ -523,7 +600,7 @@
 
     private static void addCpuData(int numberOfItems) throws IOException {
         BackingStorage storage = getAndConnectBackingStorage();
-        storage.registerCategory(CpuStatDAO.cpuStatCategory);
+        Category<AggregateCount> cat = registerCatoriesForWrite(storage, CpuStatDAO.cpuStatCategory);
 
         for (int i = 0; i < numberOfItems; i++) {
             CpuStat pojo = new CpuStat("test-agent-id", i, new double[] {i, i*2});
@@ -533,13 +610,33 @@
             add.set(Key.TIMESTAMP.getName(), pojo.getTimeStamp());
             add.apply();
         }
+        waitForDataCount(numberOfItems, storage, cat);
+        storage.getConnection().disconnect();
+    }
+    
+    private static void waitForDataCount(int expectedCount, BackingStorage storage, Category<AggregateCount> cat) {
+        long count = countAllData(storage, cat);
+        int currCount = 0;
+        final int MAX_CYCLES = 5;
+        while (count != expectedCount && currCount < MAX_CYCLES) {
+            try {
+                Thread.sleep(250);
+            } catch (InterruptedException ignored) {}
+            count = countAllData(storage, cat);
+        }
+        
+    }
 
-        storage.getConnection().disconnect();
+    private static <T extends Pojo> Category<AggregateCount> registerCatoriesForWrite(BackingStorage storage, Category<T> cat) {
+        storage.registerCategory(cat);
+        Category<AggregateCount> adaptedCategory = new CategoryAdapter<T, AggregateCount>(cat).getAdapted(AggregateCount.class);
+        storage.registerCategory(adaptedCategory);
+        return adaptedCategory;
     }
     
     private static void addHostInfoData(int numberOfItems) throws IOException {
         BackingStorage storage = getAndConnectBackingStorage();
-        storage.registerCategory(HostInfoDAO.hostInfoCategory);
+        Category<AggregateCount> cat = registerCatoriesForWrite(storage, HostInfoDAO.hostInfoCategory);
 
         for (int i = 0; i < numberOfItems; i++) {
             HostInfo hostInfo = new HostInfo("test-host-agent-id", "foo " + i, "linux " + i, "kernel", "t8", i, i * 1000);
@@ -553,13 +650,13 @@
             add.set(HostInfoDAO.osNameKey.getName(), hostInfo.getOsName());
             add.apply();
         }
-
+        waitForDataCount(numberOfItems, storage, cat);
         storage.getConnection().disconnect();
     }
     
     private static void addAgentConfigData(List<AgentInformation> items) throws IOException {
         BackingStorage storage = getAndConnectBackingStorage();
-        storage.registerCategory(AgentInfoDAO.CATEGORY);
+        Category<AggregateCount> cat = registerCatoriesForWrite(storage, AgentInfoDAO.CATEGORY);
 
         for (AgentInformation info: items) {
             Add<AgentInformation> add = storage.createAdd(AgentInfoDAO.CATEGORY);
@@ -570,7 +667,7 @@
             add.set(AgentInfoDAO.STOP_TIME_KEY.getName(), info.getStopTime());
             add.apply();
         }
-
+        waitForDataCount(items.size(), storage, cat);
         storage.getConnection().disconnect();
     }
 
@@ -582,22 +679,23 @@
         doDeleteData(HostInfoDAO.hostInfoCategory, "test-host-agent-id");
     }
     
-    private static void doDeleteData(Category<?> category, String agentId) throws IOException {
-        String[] roleNames = new String[] {
-                Roles.REGISTER_CATEGORY,
-                Roles.ACCESS_REALM,
-                Roles.LOGIN,
-                Roles.PURGE
-        };
-        Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames);
-        storage.registerCategory(category);
+    private static <T extends Pojo> void doDeleteData(Category<T> category, String agentId) throws IOException {
+        BackingStorage storage = getAndConnectBackingStorage();
+        Category<AggregateCount> cat = registerCatoriesForWrite(storage, category);
+        // FIXME: The method signature suggests it deletes data for the given agent
+        //        in the given category. But it actually deletes any records in
+        //        any category matching the agentId parameter. This should get
+        //        changed from purge to a remove operation.
         storage.purge(agentId);
+        waitForDataCount(0, storage, cat);
         storage.getConnection().disconnect();
     }
     
     private static void deleteAgentConfigData(List<AgentInformation> items) throws IOException {
         BackingStorage storage = getAndConnectBackingStorage();
-        storage.registerCategory(AgentInfoDAO.CATEGORY);
+        Category<AggregateCount> cat = registerCatoriesForWrite(storage, AgentInfoDAO.CATEGORY);
+        
+        long countPriorRemove = countAllData(storage, cat);
         ExpressionFactory factory = new ExpressionFactory();
         Remove<AgentInformation> remove = storage.createRemove(AgentInfoDAO.CATEGORY);
         Set<String> agentIds = new HashSet<>();
@@ -607,6 +705,7 @@
         Expression expression = factory.in(Key.AGENT_ID, agentIds, String.class);
         remove.where(expression);
         remove.apply();
+        waitForDataCount((int)(countPriorRemove - items.size()), storage, cat);
 
         storage.getConnection().disconnect();
     }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LauncherImpl.java	Tue Jun 23 09:57:32 2015 -0600
@@ -91,7 +91,7 @@
     private static final String SETUP_SCRIPT_NAME = "thermostat-setup";
 
     private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-    private Logger logger;
+    private static final Logger logger = LoggingUtils.getLogger(LauncherImpl.class);
 
     private final AtomicInteger usageCount = new AtomicInteger(0);
     private final BundleContext context;
@@ -130,7 +130,10 @@
         this.paths = Objects.requireNonNull(paths);
 
         loggingInitializer.initialize();
-        logger = LoggingUtils.getLogger(LauncherImpl.class);
+        // We log this in the constructor so as to not log it multiple times when a command invokes
+        // run() multiple times. This works since it is a singleton service.
+        logger.log(Level.CONFIG, "THERMOSTAT_HOME=" + paths.getSystemThermostatHome().getAbsolutePath());
+        logger.log(Level.CONFIG, "USER_THERMOSTAT_HOME=" + paths.getUserThermostatHome().getAbsolutePath());
     }
 
     @Override
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -197,6 +197,8 @@
         assertNotNull(action);
         Keyring keyringService = mock(Keyring.class);
         CommonPaths paths = mock(CommonPaths.class);
+        when(paths.getSystemThermostatHome()).thenReturn(mock(File.class));
+        when(paths.getUserThermostatHome()).thenReturn(mock(File.class));
         when(paths.getSystemLibRoot()).thenReturn(new File(""));
         when(paths.getSystemPluginRoot()).thenReturn(new File(""));
         when(paths.getUserPluginRoot()).thenReturn(new File(""));
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/LauncherImplTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.launcher.internal;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyString;
@@ -50,7 +51,9 @@
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.concurrent.ExecutorService;
+import java.util.logging.Handler;
 import java.util.logging.Level;
+import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 import org.apache.commons.cli.Option;
@@ -96,7 +99,7 @@
     private static final String name3 = "test3";
     private static final String name4 = "test4";
     private static SecurityManager secMan;
-      
+    
     @BeforeClass
     public static void beforeClassSetUp() {
         // Launcher calls System.exit(). This causes issues for unit testing.
@@ -273,6 +276,8 @@
         when(paths.getUserSetupCompleteStampFile()).thenReturn(setupFile);
         ClientPreferences prefs = new ClientPreferences(paths);
 
+        when(paths.getSystemThermostatHome()).thenReturn(mock(File.class));
+        when(paths.getUserThermostatHome()).thenReturn(mock(File.class));
         launcher = new LauncherImpl(bundleContext, ctxFactory, registry, infos, new CommandSource(bundleContext),
                 environment, dbServiceFactory, version, prefs, keyring, paths, loggingInitializer);
     }
@@ -558,6 +563,44 @@
         assertEquals(expectedVersionInfo, ctxFactory.getOutput());
         assertTrue(timerFactory.isShutdown());
     }
+    
+    /**
+     * Tests if USER_THERMOSTAT_HOME and THERMOSTAT_HOME gets logged correctly
+     * on instantiation.
+     */
+    @Test
+    public void verifyLogsUserHomeThermostatHomeOnInstantiation() {
+        Logger logger = Logger.getLogger("com.redhat.thermostat");
+        logger.setLevel(Level.ALL);
+        assertTrue(logger.getLevel() == Level.ALL);
+        TestLogHandler handler = new TestLogHandler();
+        logger.addHandler(handler);
+        ClientPreferences prefs = mock(ClientPreferences.class);
+        Keyring keyring = mock(Keyring.class);
+        CommonPaths logPaths = mock(CommonPaths.class);
+        when(logPaths.getUserThermostatHome()).thenReturn(mock(File.class));
+        when(logPaths.getSystemThermostatHome()).thenReturn(mock(File.class));
+        
+        try {
+            assertFalse(handler.loggedThermostatHome);
+            assertFalse(handler.loggedUserHome);
+            // this should trigger logging
+            new LauncherImpl(bundleContext, ctxFactory, registry,
+                    infos, new CommandSource(bundleContext),
+                    environment, dbServiceFactory,
+                    version, prefs, keyring, logPaths,
+                    loggingInitializer);
+            assertTrue(handler.loggedThermostatHome);
+            assertTrue(handler.loggedUserHome);
+            verify(logPaths).getUserThermostatHome();
+            verify(logPaths).getSystemThermostatHome();
+        } finally {
+            // clean-up in order to avoid logs for other tests.
+            logger.removeHandler(handler);
+            handler = null;
+            logger.setLevel(Level.INFO);
+        }
+    }
 
     @Test
     public void verifyListenersAdded() {
@@ -637,6 +680,35 @@
 
         ctxFactory.getCommandRegistry().registerCommand(cmdName, mockCmd);
         runAndVerifyCommand(new String[] { cmdName }, expected, isInShell);
-    }   
+    }
+    
+    private static class TestLogHandler extends Handler {
+        
+        private boolean loggedThermostatHome;
+        private boolean loggedUserHome;
+        
+        @Override
+        public void close() throws SecurityException {
+            // nothing
+        }
+
+        @Override
+        public void flush() {
+            // nothing
+        }
+
+        @Override
+        public void publish(LogRecord record) {
+            String logMessage = record.getMessage();
+            System.out.println(logMessage);
+            if (record.getLevel() == Level.CONFIG && logMessage.startsWith("THERMOSTAT_HOME")) {
+                loggedThermostatHome = true;
+            }
+            if (record.getLevel() == Level.CONFIG && logMessage.startsWith("USER_THERMOSTAT_HOME")) {
+                loggedUserHome = true;
+            }
+        }
+        
+    }
 }
 
--- a/numa/client-swing/src/test/java/com/redhat/thermostat/numa/client/swing/internal/NumaPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/numa/client-swing/src/test/java/com/redhat/thermostat/numa/client/swing/internal/NumaPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -46,12 +46,15 @@
 import org.fest.swing.fixture.Containers;
 import org.fest.swing.fixture.FrameFixture;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class NumaPanelTest {
 
--- a/pom.xml	Thu Jun 04 00:38:59 2015 -0500
+++ b/pom.xml	Tue Jun 23 09:57:32 2015 -0600
@@ -78,6 +78,25 @@
         <surefire-argline>-XX:-UseSplitVerifier -XX:MaxPermSize=300m</surefire-argline>
       </properties>
     </profile>
+    <profile>
+      <!-- Temporary workaround for PR2282: Caciocavallo tests fail with JDK 8 u40 -->
+      <id>java-8-skip-cacio-tests</id>
+      <activation>
+        <jdk>1.8</jdk>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <excludedGroups>com.redhat.thermostat.annotations.internal.CacioTest</excludedGroups>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+
+    </profile>
     <!-- Development settings for web.xml. Release builds should
          have the "environment.type=release" property. -->
     <profile>
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/Activator.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/Activator.java	Tue Jun 23 09:57:32 2015 -0600
@@ -40,8 +40,6 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 
-import com.redhat.thermostat.common.cli.CommandRegistry;
-import com.redhat.thermostat.common.cli.CommandRegistryImpl;
 import com.redhat.thermostat.storage.core.StorageProvider;
 import com.redhat.thermostat.storage.mongodb.MongoStorageProvider;
 
@@ -49,20 +47,16 @@
 
     @SuppressWarnings("rawtypes")
     private ServiceRegistration reg;
-    private CommandRegistry cmdReg;
     
     @Override
     public void start(BundleContext context) throws Exception {
         StorageProvider prov = new MongoStorageProvider();
         reg = context.registerService(StorageProvider.class.getName(), prov, null);
-        cmdReg = new CommandRegistryImpl(context);
-        cmdReg.registerCommand(AddUserCommandDispatcher.COMMAND_NAME, new AddUserCommandDispatcher(context));
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
         reg.unregister();
-        cmdReg.unregisterCommands();
     }
 
 }
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommand.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.Objects;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.StorageAuthInfoGetter;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.locale.LocalizedString;
-import com.redhat.thermostat.shared.locale.Translate;
-import com.redhat.thermostat.storage.core.DbService;
-import com.redhat.thermostat.storage.core.DbServiceFactory;
-import com.redhat.thermostat.storage.core.QueuedStorage;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-
-/**
- * This command needs to be in the mongodb storage bundle since it
- * uses MongoStorage directly (casts to it).
- *
- */
-public class AddUserCommand extends BaseAddUserCommand {
-    
-    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-    static final String DB_URL_ARG = "dbUrl";
-    private final BundleContext context;
-    private final StorageCredentials emptyCredentials;
-    
-    AddUserCommand(BundleContext context) {
-        this.context = context;
-        // These are empty credentials we'll use for the initial connect. We
-        // connect with them when the local host exception is turned off.
-        emptyCredentials = new StorageCredentials() {
-            
-            @Override
-            public String getUsername() {
-                return null;
-            }
-            
-            @Override
-            public char[] getPassword() {
-                return null;
-            }
-        };
-    }
-
-    // PRE: storage started with --permitLocalHostException.
-    // FIXME: Is there anything we can do to ensure this precondition?
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        // Check if mongodb stamp file exists.
-        ServiceReference commonPathRef = context.getServiceReference(CommonPaths.class.getName());
-        requireNonNull(commonPathRef, t.localize(LocaleResources.COMMON_PATHS_SERVICE_UNAVAILABLE));
-        CommonPaths commonPath = (CommonPaths)context.getService(commonPathRef);
-        File dataDir = commonPath.getUserPersistentDataDirectory();
-        // Since this is backing storage specific, it's most likely not a good
-        // candidate for CommonPaths
-        File mongodbSetupStamp = new File(dataDir, BaseAddUserCommand.MONGODB_STAMP_FILE_NAME);
-        if (mongodbSetupStamp.exists()) {
-            String msg = t.localize(LocaleResources.MONGODB_SETUP_FILE_EXISTS,
-                                    mongodbSetupStamp.getAbsolutePath()).getContents();
-            ctx.getConsole().getOutput().println(msg);
-            return;
-        }
-        
-        ServiceReference dbServiceRef = context.getServiceReference(DbService.class);
-        if (dbServiceRef != null) {
-            // Already connected, bail out
-            throw new CommandException(t.localize(LocaleResources.ALREADY_CONNECTED_TO_STORAGE_WARNING));
-        }
-        String dbUrl = ctx.getArguments().getArgument(DB_URL_ARG);
-        // dbUrl is a required argument. This should never happen
-        Objects.requireNonNull(dbUrl);
-        // we only understand "mongodb://" URLs
-        if (!dbUrl.startsWith("mongodb://")) {
-            throw new CommandException(t.localize(LocaleResources.UNKNOWN_STORAGE_URL));
-        }
-        
-        // Register empty credentials so that connection succeeds
-        ServiceRegistration reg = context.registerService(StorageCredentials.class.getName(), emptyCredentials, null);
-        DbServiceFactory factory = new DbServiceFactory();
-        DbService service = factory.createDbService(dbUrl);
-        // this synchronously connects to storage
-        service.connect();
-        // Unregister empty credentials
-        reg.unregister();
-        
-        ServiceReference storageRef = context.getServiceReference(Storage.class.getName());
-        requireNonNull(storageRef, t.localize(LocaleResources.STORAGE_SERVICE_UNAVAILABLE));
-        @SuppressWarnings("unchecked")
-        // FIXME: Hack alarm. We use knowledge that via MongoStorageProvider we
-        //        have a MongoStorage instance wrapped in QueuedStorage. What's
-        //        more, we use the "delegate" field name in order to get at the
-        //        MongoStorage instance, which we cast to. I'm not sure if adding
-        //        method in BackingStorage (the interface) directly would be 
-        //        any better than this. After all, this is very backing storage
-        //        impl specific. For now do this hack :-/  
-        QueuedStorage storage = (QueuedStorage)context.getService(storageRef);
-        MongoStorage mongoStorage = getDelegate(storage);
-        requireNonNull(mongoStorage, t.localize(LocaleResources.MONGOSTORAGE_RETRIEVAL_FAILED));
-        StorageAuthInfoGetter getter = null;
-        try {
-            LocalizedString userPrompt = new LocalizedString("Please enter the username you'd like to add to mongodb storage at " + dbUrl + ": ");
-            LocalizedString passWordPrompt = new LocalizedString("Please enter the desired password of this user: ");
-            getter = new StorageAuthInfoGetter(ctx.getConsole(), userPrompt, passWordPrompt);
-        } catch (IOException e) {
-            throw new CommandException(t.localize(LocaleResources.ADDING_USER_FAILED));
-        }
-        ConsoleStorageCredentials creds = new ConsoleStorageCredentials(getter);
-        addUser(mongoStorage, creds);
-        
-        // create the STAMP file
-        try {
-            mongodbSetupStamp.createNewFile();
-        } catch (IOException e) {
-            String msg = t.localize(LocaleResources.STAMP_FILE_CREATION_FAILED,
-                                    mongodbSetupStamp.getAbsolutePath()).getContents();
-            ctx.getConsole().getError().println(msg);
-            throw new CommandException(new LocalizedString(msg));
-        }
-        
-        String msg = t.localize(LocaleResources.MONGODB_USER_SETUP_COMPLETE).getContents();
-        ctx.getConsole().getOutput().println(msg);
-    }
-    
-    // package-private for testing
-    void addUser(MongoStorage mongoStorage, StorageCredentials creds) {
-        // It's important that getUsername is called prior getPassword.
-        // otherwise prompts don't make much sense.
-        String username = creds.getUsername();
-        char[] pwd = creds.getPassword();
-        mongoStorage.addUser(username, pwd);
-        // zero out password. We no longer use it.
-        Arrays.fill(pwd, '\0');
-    }
-
-    // package-private for testing
-    MongoStorage getDelegate(QueuedStorage storage) {
-        try {
-            Field field = storage.getClass().getDeclaredField("delegate");
-            field.setAccessible(true);
-            MongoStorage mongo = (MongoStorage)field.get(storage);
-            return mongo;
-        } catch (Exception e) {
-            return null;
-        }
-    }
-    
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-
-}
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandDispatcher.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.shared.locale.Translate;
-
-/**
- * Dispatcher making sure either -d or -s has been provided.
- *
- */
-class AddUserCommandDispatcher extends BaseAddUserCommand {
-    
-    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-    private static final String START_STORAGE_ARG = "startStorage";
-    private static final String DB_URL_ARG = "dbUrl";
-    static final String COMMAND_NAME = "add-mongodb-user";
-    private final BundleContext context;
-    private BaseAddUserCommand command;
-    
-    AddUserCommandDispatcher(BundleContext context, BaseAddUserCommand cmd) {
-        this.context = context;
-        this.command = cmd;
-    }
-
-    AddUserCommandDispatcher(BundleContext context) {
-        this(context, new AddUserCommand(context));
-    }
-    
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        if (ctx.getArguments().hasArgument(START_STORAGE_ARG)) {
-            // decorate and run
-            command = new StartStopAddUserCommandDecorator(context, command);
-        } else if (!ctx.getArguments().hasArgument(DB_URL_ARG)) {
-            throw new CommandException(t.localize(LocaleResources.DISPATCHER_WRONG_OPTION));
-        }
-        command.run(ctx);
-    }
-
-}
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/BaseAddUserCommand.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import com.redhat.thermostat.common.cli.AbstractCommand;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-
-/**
- * 
- * Base class for user setup decorators.
- * 
- * @see AddUserCommand
- * @see StartStopAddUserCommandDecorator
- *
- */
-abstract class BaseAddUserCommand extends AbstractCommand {
-    
-    static final String MONGODB_STAMP_FILE_NAME = "mongodb-user-done.stamp";
-    
-    @Override
-    abstract public void run(CommandContext ctx) throws CommandException;
-    
-    @Override
-    public boolean isStorageRequired() {
-        return false;
-    }
-}
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnection.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoConnection.java	Tue Jun 23 09:57:32 2015 -0600
@@ -113,7 +113,7 @@
 
     private void authenticate(String username, char[] password) {
         if (! db.authenticate(username, password)) {
-            throw new MongoException("Invalid username/password");
+            throw new MongoException("Invalid username/password: " + username + "/" + new String(password));
         }
     }
 
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorage.java	Tue Jun 23 09:57:32 2015 -0600
@@ -701,18 +701,6 @@
                     categoryInfo, true, false);
         
     }
-    
-    /*
-     * Used by add-user command.
-     * 
-     * Pre: must be connected to storage already
-     */
-    void addUser(String username, char[] password) {
-        // only create user if not already existing
-        if (!db.authenticate(username, password)) {
-            db.addUser(username, password);
-        }
-    }
 
 }
 
--- a/storage/mongo/src/main/java/com/redhat/thermostat/storage/mongodb/internal/StartStopAddUserCommandDecorator.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,268 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-
-import com.redhat.thermostat.common.ActionEvent;
-import com.redhat.thermostat.common.ActionListener;
-import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand;
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandContextFactory;
-import com.redhat.thermostat.common.cli.CommandException;
-import com.redhat.thermostat.common.tools.ApplicationState;
-import com.redhat.thermostat.launcher.Launcher;
-import com.redhat.thermostat.shared.config.CommonPaths;
-import com.redhat.thermostat.shared.locale.Translate;
-
-/*
- * A command which adds a mongdb user by using AddUserCommand. It has been
- * introduced in order to aid boot-strapping of thermostat deployments. In order
- * to set up a user in mongodb, storage needs to be started with the
- * --permitLocalhostException option first. Then the credentials need to be
- * injected and storage stopped again. This command performs all three
- * required steps.
- */
-public class StartStopAddUserCommandDecorator extends BaseAddUserCommand {
-
-    public static final String COMMAND_NAME = "admin-mongodb-creds-setup";
-    private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
-    private final BundleContext context;
-    private final List<ActionListener<ApplicationState>> listeners;
-    private final CountDownLatch setupFinishedBarrier;
-    private final BaseAddUserCommand decoratee;
-    private boolean setupSuccessful;
-    private Launcher launcher;
-    private CommandContext cmdCtx;
-    
-    StartStopAddUserCommandDecorator(BundleContext context, BaseAddUserCommand command) {
-        this.context = context;
-        this.listeners = new ArrayList<>(1);
-        this.setupFinishedBarrier = new CountDownLatch(1);
-        this.setupSuccessful = true;
-        this.decoratee = command;
-    }
-    
-    @Override
-    public void run(CommandContext ctx) throws CommandException {
-        cmdCtx = ctx;
-        if (!stampFileExists()) {
-            startStorageAndRunDecoratee();
-            stopStorage();
-        }
-        // if stamp file exists, there is nothing to do.
-        String msg;
-        if (setupSuccessful) {
-            msg = t.localize(LocaleResources.USER_SETUP_COMPLETE).getContents();
-            cmdCtx.getConsole().getOutput().println(msg);
-        } else {
-            msg = t.localize(LocaleResources.USER_SETUP_FAILED).getContents();
-            cmdCtx.getConsole().getOutput().println(msg);
-        }
-    }
-
-    private void stopStorage() throws CommandException {
-        listeners.clear();
-        CountDownLatch storageStoppedlatch = new CountDownLatch(1);
-        StorageStoppedListener listener = new StorageStoppedListener(storageStoppedlatch);
-        String[] storageStopArgs = new String[] {
-                "storage", "--stop"
-        };
-        listeners.add(listener);
-        launcher.run(storageStopArgs, listeners, false);
-        try {
-            storageStoppedlatch.await();
-        } catch (InterruptedException e) {
-            setupSuccessful = false;
-            throw new CommandException(t.localize(LocaleResources.INTERRUPTED_WAITING_FOR_STORAGE_STOP), e);
-        }
-        if (!listener.storageStopPassed) {
-            setupSuccessful = false;
-            String msg = t.localize(LocaleResources.STORAGE_STOP_FAILED).getContents();
-            cmdCtx.getConsole().getError().println(msg);
-        }
-    }
-
-    private void startStorageAndRunDecoratee() throws CommandException {
-        ServiceReference launcherRef = context.getServiceReference(Launcher.class);
-        if (launcherRef == null) {
-            throw new CommandException(t.localize(LocaleResources.LAUNCHER_SERVICE_UNAVAILABLE));
-        }
-        launcher = (Launcher) context.getService(launcherRef);
-        StorageStartedListener listener = new StorageStartedListener();
-        listeners.add(listener);
-        String[] storageStartArgs = new String[] { "storage", "--start", "--permitLocalhostException"};
-        launcher.run(storageStartArgs, listeners, false);
-        try {
-            setupFinishedBarrier.await();
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private boolean stampFileExists() throws CommandException {
-        ServiceReference commonPathRef = context.getServiceReference(CommonPaths.class.getName());
-        if (commonPathRef == null) {
-            throw new CommandException(t.localize(LocaleResources.COMMON_PATHS_SERVICE_UNAVAILABLE));
-        }
-        CommonPaths commonPath = (CommonPaths)context.getService(commonPathRef);
-        File dataDir = commonPath.getUserPersistentDataDirectory();
-        // Since this is backing storage specific, it's most likely not a good
-        // candidate for CommonPaths
-        File mongodbSetupStamp = new File(dataDir, BaseAddUserCommand.MONGODB_STAMP_FILE_NAME);
-        if (mongodbSetupStamp.exists()) {
-            String msg = t.localize(LocaleResources.MONGODB_SETUP_FILE_EXISTS,
-                                    mongodbSetupStamp.getAbsolutePath()).getContents();
-            cmdCtx.getConsole().getOutput().println(msg);
-            return true;
-        } else {
-            return false;
-        }
-    }
-    
-    private class StorageStartedListener implements ActionListener<ApplicationState> {
-     
-        @Override
-        public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-            if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) {
-                AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource();
-                // Implementation detail: there is a single StorageCommand instance registered
-                // as an OSGi service.  We remove ourselves as listener so that we don't get
-                // notified in the case that the command is invoked by some other means later.
-                storage.getNotifier().removeActionListener(this);
-                
-                try {
-                    switch (actionEvent.getActionId()) {
-                    case START:
-                        // Payload is connection URL
-                        Object payload = actionEvent.getPayload();
-                        if (payload == null || !(payload instanceof String)) {
-                            setupSuccessful = false;
-                            throw new CommandException(t.localize(LocaleResources.UNRECOGNIZED_PAYLOAD_FROM_STORAGE_CMD));
-                        }
-                        final String dbUrl = (String)payload;
-                        try {
-                            CommandContext ctx = getAddUserCommandContext(dbUrl);
-                            decoratee.run(ctx);
-                        } catch (CommandException e) {
-                            cmdCtx.getConsole().getError().println(e.getMessage());
-                            String msg = t.localize(LocaleResources.ADDING_USER_FAILED).getContents();
-                            cmdCtx.getConsole().getError().println(msg);
-                        }
-                        break;
-                    case FAIL:
-                        // nothing
-                        break;
-                    default:
-                        // nothing
-                        break;
-                    }
-                } catch (CommandException e) {
-                    cmdCtx.getConsole().getError().println(e.getMessage());
-                } finally {
-                    setupFinishedBarrier.countDown();
-                }
-            }
-            
-        }
-        
-        private CommandContext getAddUserCommandContext(final String dbUrl) {
-            CommandContextFactory factory = new CommandContextFactory(context);
-            CommandContext ctx = factory.createContext(new Arguments() {
-                
-                @Override
-                public boolean hasArgument(String name) {
-                    if (name.equals(AddUserCommand.DB_URL_ARG)) {
-                        return true;
-                    }
-                    return false;
-                }
-                
-                @Override
-                public List<String> getNonOptionArguments() {
-                    return Collections.emptyList();
-                }
-                
-                @Override
-                public String getArgument(String name) {
-                    if (name.equals(AddUserCommand.DB_URL_ARG)) {
-                        return dbUrl;
-                    }
-                    return null;
-                }
-            });
-            return ctx;
-        }
-    }
-    
-    private static class StorageStoppedListener implements ActionListener<ApplicationState> {
-
-        private boolean storageStopPassed;
-        private final CountDownLatch storageStoppedLatch;
-        private StorageStoppedListener(CountDownLatch latch) {
-            storageStoppedLatch = latch;
-        }
-        
-        @Override
-        public void actionPerformed(ActionEvent<ApplicationState> actionEvent) {
-            if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) {
-                AbstractStateNotifyingCommand storage = (AbstractStateNotifyingCommand) actionEvent.getSource();
-                // remove ourselves so that we get called more than once.
-                storage.getNotifier().removeActionListener(this);
-                switch(actionEvent.getActionId()) {
-                case STOP:
-                    storageStopPassed = true;
-                    storageStoppedLatch.countDown();
-                    break;
-                default:
-                    storageStoppedLatch.countDown();
-                    break;
-                
-                }
-            }
-        }
-        
-    }
-}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandDispatcherTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.junit.Test;
-import org.osgi.framework.BundleContext;
-
-import com.redhat.thermostat.common.cli.Arguments;
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandContextFactory;
-import com.redhat.thermostat.common.cli.CommandException;
-
-public class AddUserCommandDispatcherTest {
-
-    @Test
-    public void canRunUndecorated() {
-        BundleContext context = mock(BundleContext.class);
-        BaseAddUserCommand mockCmd = mock(BaseAddUserCommand.class);
-        AddUserCommandDispatcher dispatcher = new AddUserCommandDispatcher(context, mockCmd);
-        CommandContextFactory factory = new CommandContextFactory(context);
-        Arguments args = mock(Arguments.class);
-        when(args.hasArgument(eq("dbUrl"))).thenReturn(true);
-        CommandContext ctx = factory.createContext(args);
-        
-        // This should not throw any exception
-        try {
-            dispatcher.run(ctx);
-        } catch (CommandException e) {
-            fail(e.getMessage());
-        }
-    }
-    
-    @Test(expected = CommandException.class )
-    public void failsToRunWithNoArguments() throws CommandException {
-        BundleContext context = mock(BundleContext.class);
-        BaseAddUserCommand mockCmd = mock(BaseAddUserCommand.class);
-        AddUserCommandDispatcher dispatcher = new AddUserCommandDispatcher(context, mockCmd);
-        CommandContextFactory factory = new CommandContextFactory(context);
-        Arguments args = mock(Arguments.class);
-        when(args.hasArgument(any(String.class))).thenReturn(false);
-        CommandContext ctx = factory.createContext(args);
-        
-        // this throws CommandException
-        dispatcher.run(ctx);
-    }
-    
-    @Test
-    public void decoratesIfStorageStartOptionGiven() {
-        BundleContext context = mock(BundleContext.class);
-        BaseAddUserCommand mockCmd = mock(BaseAddUserCommand.class);
-        AddUserCommandDispatcher dispatcher = new AddUserCommandDispatcher(context, mockCmd);
-        CommandContextFactory factory = new CommandContextFactory(context);
-        Arguments args = mock(Arguments.class);
-        when(args.hasArgument(eq("startStorage"))).thenReturn(true);
-        CommandContext ctx = factory.createContext(args);
-        
-        try {
-            dispatcher.run(ctx);
-            fail("CommonPaths not available, should have thrown exception");
-        } catch (CommandException e) {
-            boolean passed = false;
-            for( StackTraceElement elmt: e.getStackTrace()) {
-                // StartStopAddUserCommandDecorator should be in stack trace
-                if (elmt.getClassName().equals(StartStopAddUserCommandDecorator.class.getName())) {
-                    passed = true;
-                    break;
-                }
-            }
-            assertTrue("Expected mocked BaseAddUserCommand to be decorated", passed);
-        }
-    }
-    
-    @Test
-    public void testCommandName() {
-        assertEquals("add-mongodb-user", AddUserCommandDispatcher.COMMAND_NAME);
-    }
-}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/AddUserCommandTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import com.mongodb.DB;
-import com.redhat.thermostat.storage.core.QueuedStorage;
-import com.redhat.thermostat.storage.core.Storage;
-import com.redhat.thermostat.storage.core.StorageCredentials;
-
-//There is a bug (resolved as wontfix) in powermock which results in
-//java.lang.LinkageError if javax.management.* classes aren't ignored by
-//Powermock. More here: http://code.google.com/p/powermock/issues/detail?id=277
-//SSL tests need this and having that annotation on method level doesn't seem
-//to solve the issue.
-@PowerMockIgnore( {"javax.management.*"})
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({ DB.class })
-public class AddUserCommandTest {
-
-    /*
-     * Verifies that credentials' methods are called in the right order and
-     * the password array is filled with zeros after use.
-     */
-    @Test
-    public void verifyAddUser() {
-        DB db = PowerMockito.mock(DB.class);
-        CountDownLatch latch = new CountDownLatch(1);
-        MongoStorage storage = new MongoStorage(db, latch);
-        
-        StorageCredentials creds = mock(StorageCredentials.class);
-        String username = "fooUser";
-        char[] password = new char[] { 'f', 'o', 'o' };
-        when(creds.getUsername()).thenReturn(username);
-        when(creds.getPassword()).thenReturn(password);
-        InOrder inOrder = inOrder(creds);
-        
-        AddUserCommand command = new AddUserCommand(null /* unused */);
-        command.addUser(storage, creds);
-        
-        // password should have been zero-filled
-        assertTrue(Arrays.equals(new char[] { '\0', '\0', '\0' }, password));
-        // First username, then password should get called.
-        inOrder.verify(creds).getUsername();
-        inOrder.verify(creds).getPassword();
-    }
-    
-    /*
-     * Verifies if the delegate can be retrieved from QueuedStorage since
-     * AddUserCommand relies on this. In particular the delegate needs to be
-     * a MongoStorage instance.
-     */
-    @Test
-    public void verifyGettingDelegateWorks() {
-        DB db = PowerMockito.mock(DB.class);
-        CountDownLatch latch = new CountDownLatch(1);
-        // Delegate must be mongostorage
-        MongoStorage storage = new MongoStorage(db, latch);
-        
-        QueuedStorage qStorage = new QueuedStorage(storage);
-        AddUserCommand command = new AddUserCommand(null /* unused */);
-        Storage actual = command.getDelegate(qStorage);
-        
-        assertSame(storage, actual);
-    }
-}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/BaseAddUserCommandTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright 2012-2015 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.storage.mongodb.internal;
-
-import static org.junit.Assert.assertFalse;
-
-import org.junit.Test;
-
-import com.redhat.thermostat.common.cli.CommandContext;
-import com.redhat.thermostat.common.cli.CommandException;
-
-public class BaseAddUserCommandTest {
-
-    @Test
-    public void storageRequiredFalse() {
-        TestAddUserCommand cmd = new TestAddUserCommand();
-        assertFalse(cmd.isStorageRequired());
-    }
-    
-    private static class TestAddUserCommand extends BaseAddUserCommand {
-
-        @Override
-        public void run(CommandContext ctx) throws CommandException {
-            // no-op
-        }
-        
-    }
-}
--- a/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/storage/mongo/src/test/java/com/redhat/thermostat/storage/mongodb/internal/MongoStorageTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -871,48 +871,6 @@
         assertFalse(bool2.getValue());
     }
     
-    /*
-     * AddUserCommand family use this API. Tests that working
-     * credentials don't get recreated, since this would fail
-     * anyway.
-     */
-    @Test
-    public void verifyExistingUserIsNotAdded() throws Exception {
-        DB db = PowerMockito.mock(DB.class);
-        CountDownLatch latch = new CountDownLatch(1);
-        MongoStorage storage = new MongoStorage(db, latch);
-        
-        String username = "testUser";
-        char password[] = new char[] { 'f', 'o', 'o' };
-        when(db.authenticate(eq(username), eq(password))).thenReturn(true);
-        
-        // This should not have called db.addUser() 
-        storage.addUser(username, password);
-        
-        verify(db, times(0)).addUser(any(String.class), any(char[].class));
-    }
-    
-    /*
-     * AddUserCommand family use this API. Tests that working
-     * credentials don't get recreated, since this would fail
-     * anyway.
-     */
-    @Test
-    public void verifyNotExistingUserAdded() throws Exception {
-        DB db = PowerMockito.mock(DB.class);
-        CountDownLatch latch = new CountDownLatch(1);
-        MongoStorage storage = new MongoStorage(db, latch);
-        
-        String username = "testUser";
-        char password[] = new char[] { 'f', 'o', 'o' };
-        when(db.authenticate(eq(username), eq(password))).thenReturn(false);
-        
-        // This should not have called db.addUser() 
-        storage.addUser(username, password);
-        
-        verify(db).addUser(eq(username), eq(password));
-    }
-    
     private static class FakeDataClass implements Pojo {};
 }
 
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/DistributionInformation.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/DistributionInformation.java	Tue Jun 23 09:57:32 2015 -0600
@@ -66,7 +66,13 @@
     // package-private for testing
     static DistributionInformation get(EtcOsRelease etcOsRelease, LsbRelease lsbRelease) {
         try {
-            return etcOsRelease.getDistributionInformation();
+            DistributionInformation etcOsDistroInfo = etcOsRelease.getDistributionInformation();
+            // if both name and version are unknown defer to lsb fallback
+            if (!DistributionInformation.UNKNOWN_NAME.equals(etcOsDistroInfo.getName()) &&
+                !DistributionInformation.UNKNOWN_VERSION.equals(etcOsDistroInfo.getVersion())) {
+                return etcOsDistroInfo;
+            }
+            logger.log(Level.FINE, "/etc/os-release existing, but does not contain useful info");
         } catch (IOException e) {
             // Log only at level FINE, since we have the LSB fallback
             logger.log(Level.FINE, "unable to use os-release", e);
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/EtcOsRelease.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/EtcOsRelease.java	Tue Jun 23 09:57:32 2015 -0600
@@ -44,6 +44,7 @@
 
 public class EtcOsRelease implements DistributionInformationSource {
 
+    private static final String EMPTY_STRING = "";
     private static final String OS_RELEASE = "/etc/os-release";
     private final String osReleaseFile;
     
@@ -72,10 +73,15 @@
     }
 
     public DistributionInformation getFromOsRelease(BufferedReader reader) throws IOException {
-        String name = "Linux";
         String version = DistributionInformation.UNKNOWN_VERSION;
+        String name = DistributionInformation.UNKNOWN_NAME;
         String line = null;
         while ((line = reader.readLine()) != null) {
+            // skip whitespace only lines
+            line = line.trim();
+            if (line.equals(EMPTY_STRING)) {
+                continue;
+            }
             if (line.matches("^NAME *=.*")) {
                 name = readShellVariable(line);
             }
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/DistributionInformationTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/DistributionInformationTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -37,7 +37,10 @@
 package com.redhat.thermostat.backend.system;
 
 import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
+import java.io.IOException;
 import java.util.logging.Handler;
 import java.util.logging.Logger;
 
@@ -115,6 +118,23 @@
         assertEquals(DistributionInformation.UNKNOWN_NAME, info.getName());
         assertEquals(DistributionInformation.UNKNOWN_VERSION, info.getVersion());
     }
+    
+    @Test
+    public void verifyFallbackToLsbWhenEtcOsReturnsUnknown() throws IOException {
+        EtcOsRelease mockEtcOsRelease = mock(EtcOsRelease.class);
+        DistributionInformation mockDistro = mock(DistributionInformation.class);
+        when(mockEtcOsRelease.getDistributionInformation()).thenReturn(mockDistro);
+        when(mockDistro.getName()).thenReturn(DistributionInformation.UNKNOWN_NAME);
+        when(mockDistro.getVersion()).thenReturn(DistributionInformation.UNKNOWN_VERSION);
+        
+        LsbRelease mockLsbRelease = mock(LsbRelease.class);
+        DistributionInformation mockLsbDistro = mock(DistributionInformation.class);
+        when(mockLsbRelease.getDistributionInformation()).thenReturn(mockLsbDistro);
+        
+        DistributionInformation info = DistributionInformation.get(mockEtcOsRelease, mockLsbRelease);
+        assertSame("Expected lsb info to be used since etc returns unknown",
+                   mockLsbDistro, info);
+    }
 
     private void assertTestHandlerRegistered() {
         assertNotNull(logger);
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/EtcOsReleaseTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/EtcOsReleaseTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -87,6 +87,23 @@
         assertEquals("12.1 (Asparagus)", info.getVersion());
     }
     
+    /**
+     * DistributionInformation falls back on LSB when /etc/os-release contains
+     * inconclusive content (empty in this case). It should not return some
+     * info as "Linux".
+     * 
+     * @throws IOException
+     */
+    @Test
+    public void testEmpty() throws IOException {
+        String output = "";
+        BufferedReader reader = new BufferedReader(new StringReader(output));
+        
+        DistributionInformation info = new EtcOsRelease().getFromOsRelease(reader);
+        assertEquals(DistributionInformation.UNKNOWN_NAME, info.getName());
+        assertEquals(DistributionInformation.UNKNOWN_VERSION, info.getVersion());
+    }
+    
     @Test
     public void getDistributionInformationThrowsIOExceptionIfFileNotThere() {
         EtcOsRelease etcOsRelease = new EtcOsRelease(NOT_EXISTING_OS_RELEASE_FILE);
--- a/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/thread/client-swing/src/test/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadViewTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.thread.client.swing.impl;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.UIDefaults;
 import com.redhat.thermostat.shared.locale.Translate;
 import com.redhat.thermostat.thread.client.common.locale.LocaleResources;
@@ -61,6 +62,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class SwingThreadViewTest {
 
--- a/vm-classstat/client-swing/src/test/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-classstat/client-swing/src/test/java/com/redhat/thermostat/vm/classstat/client/swing/VmClassStatPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -51,10 +51,13 @@
 import org.fest.swing.edt.GuiTask;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.storage.model.DiscreteTimeData;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class VmClassStatPanelTest {
 
--- a/vm-gc/remote-collector-client-swing/src/test/java/com/redhat/thermostat/gc/remote/client/swing/ToolbarGCButtonTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-gc/remote-collector-client-swing/src/test/java/com/redhat/thermostat/gc/remote/client/swing/ToolbarGCButtonTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -57,12 +57,15 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.components.HeaderPanel;
 import com.redhat.thermostat.shared.locale.LocalizedString;
 import com.redhat.thermostat.gc.remote.client.common.RequestGCAction;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class ToolbarGCButtonTest {
 
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwingTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDetailsSwingTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -58,14 +58,14 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.EdtHelper;
 import com.redhat.thermostat.shared.locale.LocalizedString;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.HeapDetailsSwing;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.HistogramPanel;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.ObjectDetailsPanel;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class HeapDetailsSwingTest {
 
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDumpListViewTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapDumpListViewTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -59,8 +59,10 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapDumpListView;
@@ -68,6 +70,7 @@
 
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class HeapDumpListViewTest {
 
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -48,7 +48,6 @@
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 
 import org.fest.swing.annotation.GUITest;
-import org.fest.swing.core.Robot;
 import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiTask;
@@ -65,8 +64,10 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.components.OverlayPanel;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
@@ -79,6 +80,7 @@
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
 import com.redhat.thermostat.vm.heap.analysis.common.model.HeapInfo;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class HeapSwingViewTest {
 
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanelTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectDetailsPanelTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -64,17 +64,19 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.client.swing.components.SearchField;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectDetailsView.ObjectAction;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.ObjectDetailsPanel;
 import com.sun.tools.hat.internal.model.JavaClass;
 import com.sun.tools.hat.internal.model.JavaHeapObject;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class ObjectDetailsPanelTest {
 
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectRootsFrameTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/ObjectRootsFrameTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -60,16 +60,18 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.vm.heap.analysis.client.core.HeapObjectUI;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView;
 import com.redhat.thermostat.vm.heap.analysis.client.core.ObjectRootsView.Action;
-import com.redhat.thermostat.vm.heap.analysis.client.swing.internal.ObjectRootsFrame;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class ObjectRootsFrameTest {
 
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/OverlayComponentTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/stats/OverlayComponentTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -60,10 +60,13 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.vm.heap.analysis.common.HeapDump;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class OverlayComponentTest {
 
--- a/vm-jmx/client-swing/src/test/java/com/redhat/thermostat/vm/jmx/client/swing/internal/JmxNotificationsSwingViewProviderTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-jmx/client-swing/src/test/java/com/redhat/thermostat/vm/jmx/client/swing/internal/JmxNotificationsSwingViewProviderTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -39,7 +39,11 @@
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
+
+@Category(CacioTest.class)
 public class JmxNotificationsSwingViewProviderTest {
 
     @Test
--- a/vm-memory/client-swing/src/test/java/com/redhat/thermostat/vm/memory/client/swing/internal/MemoryStatsViewImplTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-memory/client-swing/src/test/java/com/redhat/thermostat/vm/memory/client/swing/internal/MemoryStatsViewImplTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -54,10 +54,12 @@
 import org.junit.experimental.categories.Category;
 import org.junit.runner.RunWith;
 
+import com.redhat.thermostat.annotations.internal.CacioTest;
 import com.redhat.thermostat.vm.memory.client.core.MemoryStatsView;
 
 import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner;
 
+@Category(CacioTest.class)
 @RunWith(CacioFESTRunner.class)
 public class MemoryStatsViewImplTest {
 
--- a/vm-profiler/jvm-agent/pom.xml	Thu Jun 04 00:38:59 2015 -0500
+++ b/vm-profiler/jvm-agent/pom.xml	Tue Jun 23 09:57:32 2015 -0600
@@ -96,5 +96,11 @@
       <artifactId>asm-all</artifactId>
       <version>${asm.version}</version>
     </dependency>
+    <dependency>
+      <groupId>com.redhat.thermostat</groupId>
+      <artifactId>thermostat-annotations</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/ConfigurationFinder.java	Tue Jun 23 09:57:32 2015 -0600
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2015 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.web.server;
+
+import java.io.File;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+
+public class ConfigurationFinder {
+
+    private final CommonPaths paths;
+
+    public ConfigurationFinder(CommonPaths paths) {
+        this.paths = paths;
+    }
+
+    /** Finds the best configuration file, accessible to the process */
+    public File getConfiguration(String name) {
+        File systemFile = getConfigurationFile(paths.getSystemConfigurationDirectory(), name);
+        if (isUsable(systemFile)) {
+            return systemFile;
+        }
+        File userFile = getConfigurationFile(paths.getUserConfigurationDirectory(), name);
+        if (isUsable(userFile)) {
+            return userFile;
+        }
+        return null;
+    }
+
+    /** package-private for testing only */
+    File getConfigurationFile(File directory, String name) {
+        return new File(directory, name);
+    }
+
+    private boolean isUsable(File file) {
+        return file.isFile() && file.canRead();
+    }
+}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java	Tue Jun 23 09:57:32 2015 -0600
@@ -148,6 +148,7 @@
     private Storage storage;
     private Gson gson;
     private CommonPaths paths;
+    private ConfigurationFinder finder;
 
     public static final String STORAGE_ENDPOINT = "storage.endpoint";
     public static final String STORAGE_CLASS = "storage.class";
@@ -167,8 +168,10 @@
     }
     
     // Package private for testing
-    WebStorageEndPoint(TimerRegistry timerRegistry) {
+    WebStorageEndPoint(TimerRegistry timerRegistry, CommonPaths paths, ConfigurationFinder finder) {
         this.timerRegistry = timerRegistry;
+        this.paths = paths;
+        this.finder = finder;
     }
 
     @Override
@@ -244,7 +247,7 @@
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
         if (storage == null) {
-            StorageCredentials creds = getStorageCredentials(paths);
+            StorageCredentials creds = getStorageCredentials();
             // if creds are null there is no point to continue, fail prominently.
             if (creds == null) {
                 String errorMsg = "No backing storage credentials file (" + CREDENTIALS_FILE + ") available";
@@ -283,44 +286,41 @@
     }
     
     // package private for testing
-    StorageCredentials getStorageCredentials(CommonPaths commonPaths) throws IOException {
-        File systemFile = getStorageCredentialsFile(commonPaths.getSystemConfigurationDirectory());
-        if (systemFile.exists() && systemFile.canRead()) {
-            logger.log(Level.CONFIG, "Loading authentication data from " + systemFile);
-            return createStorageCredentials(systemFile);
+    StorageCredentials getStorageCredentials() throws IOException {
+        File credentialsFile = finder.getConfiguration(CREDENTIALS_FILE);
+        if (credentialsFile != null) {
+            logger.log(Level.CONFIG, "Loading authentication data from " + credentialsFile);
+            return createStorageCredentials(credentialsFile);
         } else {
-            File userCredentials = getStorageCredentialsFile(commonPaths.getUserConfigurationDirectory());
-            logger.log(Level.CONFIG, "Loading authentication data from " + userCredentials);
-            if (userCredentials.isFile() && userCredentials.canRead()) {
-                return createStorageCredentials(userCredentials);
-            } else {
-                logger.warning("Unable to read database credentials from " + userCredentials);
-                return null;
-            }
+            logger.warning("Unable to read database credentials.");
+            return null;
         }
     }
     
     // package private for testing
-    File getStorageCredentialsFile(File parent) {
-        return new File(parent, CREDENTIALS_FILE);
-    }
-    
-    // package private for testing
     StorageCredentials createStorageCredentials(File underlyingFile) {
         return new FileBasedStorageCredentials(underlyingFile);
     }
 
     // Side effect: sets this.paths
     private void sanityCheckNecessaryFiles() {
-        try {
-            // Throws config exception if basic sanity checks for
-            // THERMOSTAT_HOME don't pass.
-            paths = new CommonPathsImpl();
-        } catch (InvalidConfigurationException e) {
-            logger.log(Level.SEVERE, e.getMessage());
-            throw new RuntimeException(e);
+        if (paths == null) { // for unit tests, we inject this instance
+            try {
+                // Throws config exception if basic sanity checks for
+                // THERMOSTAT_HOME don't pass.
+                paths = new CommonPathsImpl();
+            } catch (InvalidConfigurationException e) {
+                logger.log(Level.SEVERE, e.getMessage());
+                throw new RuntimeException(e);
+            }
         }
+
+        if (finder == null) { // for unit tests, we inject this instance
+            finder = new ConfigurationFinder(paths);
+        }
+
         File thermostatHomeFile = getThermostatHome();
+
         String notReadableMsg = " is not readable or does not exist!";
         // we need to be able to read ssl config for backing storage
         // paths got set in isThermostatHomeSet()
@@ -331,7 +331,7 @@
             logger.log(Level.SEVERE, msg);
             throw new RuntimeException(msg);
         }
-        // Thermost home looks OK and seems usable
+        // Thermostat home looks OK and seems usable
         logger.log(Level.FINEST, "THERMOSTAT_HOME == "
                 + thermostatHomeFile.getAbsolutePath());
     }
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java	Tue Jun 23 09:57:32 2015 -0600
@@ -48,6 +48,7 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
+import com.redhat.thermostat.web.server.ConfigurationFinder;
 
 /**
  * 
@@ -63,11 +64,15 @@
     PropertiesUserValidator() {
         // this is the default configuration. it should be overriden through different means
         // see javadoc of PropertiesUsernameRolesLoginModule
-        this((new CommonPathsImpl().getSystemConfigurationDirectory() + File.separator + DEFAULT_USERS_FILE));
+        this(new ConfigurationFinder(new CommonPathsImpl()).getConfiguration(DEFAULT_USERS_FILE));
     }
     
     PropertiesUserValidator(String usersFile) {
-        loadUsers(new File(usersFile));
+        this(new File(usersFile));
+    }
+
+    PropertiesUserValidator(File file) {
+        loadUsers(file);
     }
 
     @Override
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java	Tue Jun 23 09:57:32 2015 -0600
@@ -53,6 +53,7 @@
 import com.redhat.thermostat.common.utils.LoggingUtils;
 import com.redhat.thermostat.shared.config.InvalidConfigurationException;
 import com.redhat.thermostat.shared.config.internal.CommonPathsImpl;
+import com.redhat.thermostat.web.server.ConfigurationFinder;
 import com.redhat.thermostat.web.server.auth.BasicRole;
 import com.redhat.thermostat.web.server.auth.RolePrincipal;
 
@@ -75,12 +76,16 @@
         // this is the default configuration supplied with thermostat
         // it should not be overriden by editing this configuraton file
         // see javadocs of PropertiesUsernameRolesLoginModule
-        this((new CommonPathsImpl().getSystemConfigurationDirectory() + File.separator + DEFAULT_ROLES_FILE), users);
+        this(new ConfigurationFinder(new CommonPathsImpl()).getConfiguration(DEFAULT_ROLES_FILE), users);
     }
     
     RolesAmender(String rolesFile, Set<Object> users) {
+        this(new File(rolesFile), users);
+    }
+
+    RolesAmender(File rolesFile, Set<Object> users) {
         this.users = Objects.requireNonNull(users);
-        loadRoles(new File(rolesFile));
+        loadRoles(rolesFile);
     }
     
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/ConfigurationFinderTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012-2015 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.web.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.shared.config.CommonPaths;
+
+public class ConfigurationFinderTest {
+
+    private File systemConfigDir = mock(File.class);
+    private File userConfigDir = mock(File.class);
+
+    private File realFile1;
+    private File realFile2;
+
+    private CommonPaths paths;
+
+    @Before
+    public void setUp() throws IOException {
+        realFile1 = Files.createTempFile("configfinder-unit-test", null).toFile();
+        realFile1.createNewFile();
+
+        realFile2 = Files.createTempFile("configfinder-unit-test", null).toFile();
+        realFile2.createNewFile();
+
+        paths = mock(CommonPaths.class);
+        when(paths.getSystemConfigurationDirectory()).thenReturn(systemConfigDir);
+        when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir);
+    }
+
+    @After
+    public void tearDown() {
+        realFile1.delete();
+        realFile2.delete();
+    }
+
+    @Test
+    public void verifyFileFromUserHomeIsUsedIfSystemHomeIsNotUsable() throws Exception {
+        ConfigurationFinder finder = new ConfigurationFinder(paths) {
+            @Override
+            File getConfigurationFile(File directory, String name) {
+                if (directory == systemConfigDir) {
+                    return new File("/does-not-exist/really-it-doesn't");
+                } else if (directory == userConfigDir) {
+                    return realFile1;
+                }
+                throw new AssertionError("Unknown test case");
+            };
+        };
+
+        File config = finder.getConfiguration("web.auth");
+        assertEquals(realFile1, config);
+    }
+
+    @Test
+    public void verifyFileFromSystemHomeIsUsedIfBothAreUsable() throws IOException {
+        final File systemFile = realFile1;
+        final File userFile = realFile2;
+
+        ConfigurationFinder finder = new ConfigurationFinder(paths) {
+            @Override
+            File getConfigurationFile(File directory, String name) {
+                if (directory == systemConfigDir) {
+                    return systemFile;
+                } else if (directory == userConfigDir) {
+                    return userFile;
+                }
+                throw new AssertionError("Unknown test case");
+            };
+        };
+
+        File config = finder.getConfiguration("web.auth");
+        assertEquals(systemFile, config);
+    }
+
+    @Test
+    public void verifyFileFromSystemHomeIsUsedIfUserHomeNotUsable() throws IOException {
+        ConfigurationFinder finder = new ConfigurationFinder(paths) {
+            @Override
+            File getConfigurationFile(File directory, String name) {
+                if (directory == systemConfigDir) {
+                    return realFile1;
+                } else if (directory == userConfigDir) {
+                    return new File("/does-not-exist/really-it-doesn't");
+                }
+                throw new AssertionError("Unknown test case");
+            };
+        };
+
+        File config = finder.getConfiguration("web.auth");
+        assertEquals(realFile1, config);
+    }
+
+}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndPointUnitTest.java	Thu Jun 04 00:38:59 2015 -0500
+++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndPointUnitTest.java	Tue Jun 23 09:57:32 2015 -0600
@@ -248,116 +248,24 @@
     @Test
     public void testShutDownCancelsTimers() {
         TimerRegistry registry = mock(TimerRegistry.class);
-        WebStorageEndPoint endpoint = new WebStorageEndPoint(registry);
+        WebStorageEndPoint endpoint = new WebStorageEndPoint(registry, null, null);
         endpoint.destroy();
         verify(registry).shutDown();
     }
     
     /**
-     * Storage credentials should be read from USER_THERMOSTAT_HOME if
-     * relevant credentials file is not readable or does not exist in
-     * THERMOSTAT_HOME.
-     * 
-     * Only the user file is readable.
-     * 
-     * @throws IOException 
-     */
-    @Test
-    public void canGetUserStorageCredentials() throws IOException {
-        StorageCredsTestSetupResult setupResult = setupForStorageCredentialsTest(false, true);
-        WebStorageEndPoint endPoint = setupResult.endpoint;
-        CommonPaths paths = setupResult.commonPaths;
-        StorageCredentials creds = endPoint.getStorageCredentials(paths);
-        assertNotNull(creds);
-        assertTrue(creds instanceof TestStorageCredentials);
-        TestStorageCredentials testCreds = (TestStorageCredentials)creds;
-        assertTrue(setupResult.userCredsFile == testCreds.underlyingFile);
-    }
-    
-    /**
-     * If Storage credentials file exists and is readable it should
-     * get used over USER_THERMOSTAT_HOME's version. In this test *both*
-     * files are present and readable.
-     * 
-     * @throws IOException 
-     */
-    @Test
-    public void canGetSystemStorageCredentialsBothReadable() throws IOException {
-        StorageCredsTestSetupResult setupResult = setupForStorageCredentialsTest(true, true);
-        WebStorageEndPoint endPoint = setupResult.endpoint;
-        CommonPaths paths = setupResult.commonPaths;
-        StorageCredentials creds = endPoint.getStorageCredentials(paths);
-        assertNotNull(creds);
-        assertTrue(creds instanceof TestStorageCredentials);
-        TestStorageCredentials testCreds = (TestStorageCredentials)creds;
-        assertTrue(setupResult.systemCredsFile == testCreds.underlyingFile);
-    }
-    
-    /**
-     * If Storage credentials file exists and is readable it should
-     * get used over USER_THERMOSTAT_HOME's version. In this test only the
-     * system version is readable.
-     * 
-     * @throws IOException 
-     */
-    @Test
-    public void canGetSystemStorageCredentialsOnlySystemReadable() throws IOException {
-        StorageCredsTestSetupResult setupResult = setupForStorageCredentialsTest(true, false);
-        WebStorageEndPoint endPoint = setupResult.endpoint;
-        CommonPaths paths = setupResult.commonPaths;
-        StorageCredentials creds = endPoint.getStorageCredentials(paths);
-        assertNotNull(creds);
-        assertTrue(creds instanceof TestStorageCredentials);
-        TestStorageCredentials testCreds = (TestStorageCredentials)creds;
-        assertTrue(setupResult.systemCredsFile == testCreds.underlyingFile);
-    }
-    
-    private StorageCredsTestSetupResult setupForStorageCredentialsTest(boolean systemCanRead, boolean userCanRead) {
-        final File systemCredsFile = mock(File.class);
-        when(systemCredsFile.canRead()).thenReturn(systemCanRead);
-        when(systemCredsFile.exists()).thenReturn(true);
-        when(systemCredsFile.getPath()).thenReturn("system_creds_file");
-        final File systemCredsDirectory = mock(File.class);
-        final File userCredsDirectory = mock(File.class);
-        final File userCredsFile = mock(File.class);
-        when(userCredsFile.canRead()).thenReturn(userCanRead);
-        when(userCredsFile.isFile()).thenReturn(true);
-        when(userCredsFile.getPath()).thenReturn("user_creds_file");
-        CommonPaths paths = mock(CommonPaths.class);
-        when(paths.getSystemConfigurationDirectory()).thenReturn(systemCredsDirectory);
-        when(paths.getUserConfigurationDirectory()).thenReturn(userCredsDirectory);
-        @SuppressWarnings("serial")
-        WebStorageEndPoint endpoint = new WebStorageEndPoint() {
-            @Override
-            File getStorageCredentialsFile(File parent) {
-                // intentionally compare exact instances
-                if (systemCredsDirectory == parent) {
-                    return systemCredsFile;
-                }
-                // intentionally compare exact instances
-                if (userCredsDirectory == parent) {
-                    return userCredsFile;
-                }
-                return null;
-            }
-            
-            @Override
-            StorageCredentials createStorageCredentials(File underlyingFile) {
-                return new TestStorageCredentials(underlyingFile);
-            }
-        };
-        return new StorageCredsTestSetupResult(endpoint, paths, systemCredsFile, userCredsFile);
-    }
-    
-    /**
-     * If neither storage credentials exist (none in USER_THERMOSTAT_HOME *and*
-     * in THERMOSTAT_HOME) then null is expected to get returned.
-     * @throws IOException 
+     * If storage credentials are not found then null is expected to get returned.
      */
     @Test
     public void storageCredentialsNull() throws IOException {
-        StorageCredsTestSetupResult setupResult = setupForStorageCredentialsTest(false, false);
-        StorageCredentials creds = setupResult.endpoint.getStorageCredentials(setupResult.commonPaths);
+        CommonPaths paths = mock(CommonPaths.class);
+        TimerRegistry registry = mock(TimerRegistry.class);
+        ConfigurationFinder finder = mock(ConfigurationFinder.class);
+        when(finder.getConfiguration("web.auth")).thenReturn(null);
+
+        WebStorageEndPoint endpoint = new WebStorageEndPoint(registry, paths, finder);
+        StorageCredentials creds = endpoint.getStorageCredentials();
+
         assertNull(creds);
     }
     
@@ -387,42 +295,4 @@
         }
     }
     
-    private static class StorageCredsTestSetupResult {
-        private WebStorageEndPoint endpoint;
-        private CommonPaths commonPaths;
-        private File systemCredsFile;
-        private File userCredsFile;
-        
-        private StorageCredsTestSetupResult(WebStorageEndPoint endpoint,
-                                            CommonPaths commonPaths,
-                                            File systemCredsFile,
-                                            File userCredsFile) {
-            this.endpoint = endpoint;
-            this.commonPaths = commonPaths;
-            this.systemCredsFile = systemCredsFile;
-            this.userCredsFile = userCredsFile;
-        }
-        
-    }
-    
-    private static class TestStorageCredentials implements StorageCredentials {
-
-        private File underlyingFile;
-        
-        private TestStorageCredentials(File underlyingFile) {
-            this.underlyingFile = underlyingFile;
-        }
-        
-        @Override
-        public String getUsername() {
-            throw new AssertionError("not implemented");
-        }
-
-        @Override
-        public char[] getPassword() {
-            throw new AssertionError("not implemented");
-        }
-        
-    }
-    
 }