changeset 1174:02bf4c95c96d

Eliminate sporadic test failures due to order dependencies in WebAppTest reviewed-by: omajid, jerboaa review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-July/007513.html
author Jon VanAlten <jon.vanalten@redhat.com>
date Thu, 18 Jul 2013 09:44:45 -0600
parents f34f23da58f8
children 53d3cab77025
files integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java
diffstat 1 files changed, 395 insertions(+), 295 deletions(-) [+]
line wrap: on
line diff
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Fri Jul 12 16:03:07 2013 -0600
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Thu Jul 18 09:44:45 2013 -0600
@@ -51,45 +51,132 @@
 import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Properties;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.component.LifeCycle;
 import org.eclipse.jetty.util.component.LifeCycle.Listener;
 import org.eclipse.jetty.webapp.WebAppContext;
-import org.junit.After;
 import org.junit.AfterClass;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.redhat.thermostat.common.ApplicationInfo;
+import com.redhat.thermostat.host.cpu.common.CpuStatDAO;
+import com.redhat.thermostat.host.cpu.common.model.CpuStat;
 import com.redhat.thermostat.storage.config.ConnectionConfiguration;
 import com.redhat.thermostat.storage.config.StartupConfiguration;
 import com.redhat.thermostat.storage.core.Add;
+import com.redhat.thermostat.storage.core.Connection.ConnectionListener;
+import com.redhat.thermostat.storage.core.Connection.ConnectionStatus;
 import com.redhat.thermostat.storage.core.Cursor;
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.core.Query;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.storage.core.Query.SortDirection;
 import com.redhat.thermostat.storage.query.Expression;
 import com.redhat.thermostat.storage.query.ExpressionFactory;
 import com.redhat.thermostat.test.FreePortFinder;
 import com.redhat.thermostat.test.FreePortFinder.TryPort;
 import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO;
 import com.redhat.thermostat.vm.classstat.common.model.VmClassStat;
+import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO;
+import com.redhat.thermostat.vm.cpu.common.model.VmCpuStat;
 import com.redhat.thermostat.web.client.internal.WebStorage;
 import com.redhat.thermostat.web.server.auth.Roles;
 
 import expectj.Spawn;
 
+/*
+ * This test class starts up a mongod instance and a web storage instance
+ * (in jetty container) in front of that.  Tests should make their own
+ * connection to the web storage, probably by making use of one of the
+ * getAndConnectStorage() method variants.
+ * 
+ * Because the storage instance is shared among all of the tests, it is
+ * necessary to take precautions to avoid introducing data dependencies
+ * between tests.  Such precautions could include: using a different
+ * category (ie mongod collection) than any other existing test; setting
+ * a unique agent-id for all data written and then deleting the data
+ * at the end of the test; <insert other clever idea here>.
+ * 
+ * Please don't introduce any more sporadic test failures to this
+ * integration test!!!
+ */
 public class WebAppTest extends IntegrationTest {
 
+    private class CountdownConnectionListener implements ConnectionListener {
+
+        private final ConnectionStatus target;
+        private final CountDownLatch latch;
+        private final AtomicBoolean indicator;
+
+        private CountdownConnectionListener(ConnectionStatus target, CountDownLatch latch, AtomicBoolean indicator) {
+            this.target = target;
+            this.latch = latch;
+            this.indicator = indicator;
+        }
+
+        @Override
+        public void changed(ConnectionStatus newStatus) {
+            indicator.set(true);
+            assertEquals(target, newStatus);
+            latch.countDown();
+        }
+    }
+
+    private static class WebAppContextListener implements Listener {
+        private Throwable cause;
+        private boolean failed = false;
+        private final CountDownLatch contextStartedLatch;
+        private WebAppContextListener(CountDownLatch latch) {
+            this.contextStartedLatch = latch;
+        }
+
+        @Override
+        public void lifeCycleStarting(LifeCycle event) {
+            // nothing
+        }
+
+        @Override
+        public void lifeCycleStarted(LifeCycle event) {
+            contextStartedLatch.countDown();
+        }
+
+        @Override
+        public void lifeCycleFailure(LifeCycle event, Throwable cause) {
+            this.failed = true;
+            this.cause = cause;
+            contextStartedLatch.countDown();
+        }
+
+        @Override
+        public void lifeCycleStopping(LifeCycle event) {
+            // nothing
+        }
+
+        @Override
+        public void lifeCycleStopped(LifeCycle event) {
+            // nothing
+        }
+    }
+
+    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 = getThermostatHome() +
             "/etc/thermostat-users.properties";
     private static final String THERMOSTAT_ROLES_FILE = getThermostatHome() +
             "/etc/thermostat-roles.properties";
-    private static WebStorage webStorage;
+
+    private ExpressionFactory factory = new ExpressionFactory();
+
     private static Server server;
     private static int port;
     private static Path backupUsers;
@@ -110,9 +197,81 @@
         backupUsers.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);
+
+
+        // start the server, deploy the war
+        port = FreePortFinder.findFreePort(new TryPort() {
+            
+            @Override
+            public void tryPort(int port) throws Exception {
+                startServer(port);
+            }
+        });
+
+        addCpuData(4);
+    }
+
+    @AfterClass
+    public static void tearDownOnce() throws Exception {
+        deleteCpuData();
+
+        Spawn storage = spawnThermostat("storage", "--stop");
+        storage.expect("server shutdown complete");
+        storage.expectClose();
+        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+
+        server.stop();
+        server.join();
+
+        Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
+        Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
+    }
+
+    /*
+     * Using the given username and password, set up a user for JAAS in the web app,
+     * with the given roles, and make a storage connection to the web app (returning
+     * the Storage object).
+     */
+    private static Storage getAndConnectStorage(String username, String password,
+                                                String[] roleNames) throws IOException {
+        return getAndConnectStorage(username, password, roleNames, null);
+    }
+
+    /*
+     * Using the given username and password, set up a user for JAAS in the web app,
+     * with the given roles, and make a connection to the web app (returning the
+     * Storage object).  Before initiating the connection, add the ConnectionListener
+     * to Storage.
+     */
+    private static Storage getAndConnectStorage(String username, String password,
+                                                String[] roleNames,
+                                                ConnectionListener listener) throws IOException {
+        setupJAASForUser(roleNames, username, password);
+        String url = "http://localhost:" + port + "/thermostat/storage";
+        StartupConfiguration config = new ConnectionConfiguration(url, username, password);
+        Storage storage = new WebStorage(config);
+        if (listener != null) {
+            storage.getConnection().addListener(listener);
+        }
+        storage.getConnection().connect();
+        return storage;
+    }
+
+    private static void setupJAASForUser(String[] roleNames, String user,
+            String password) throws IOException {
+        Properties userProps = new Properties();
+        userProps.put(user, password);
+        Properties roleProps = new Properties();
+        StringBuffer roles = new StringBuffer();
+        for (int i = 0; i < roleNames.length - 1; i++) {
+            roles.append(roleNames[i] + ", ");
+        }
+        roles.append(roleNames[roleNames.length - 1]);
+        roleProps.put(user, roles.toString());
+        writeThermostatUsersRolesFile(userProps, roleProps);
     }
     
-    private void writeThermostatUsersRolesFile(Properties usersContent, Properties rolesContent) throws IOException {
+    private static void writeThermostatUsersRolesFile(Properties usersContent, Properties rolesContent) throws IOException {
         File thermostatUsers = new File(THERMOSTAT_USERS_FILE);
         File thermostatRoles = new File(THERMOSTAT_ROLES_FILE);
         try (FileOutputStream usersStream = new FileOutputStream(thermostatUsers)) {
@@ -122,36 +281,6 @@
             rolesContent.store(rolesStream, "integration-test roles");
         }
     }
-    
-    @Before
-    public void setup() throws Exception {
-        // start the server, deploy the war
-        port = FreePortFinder.findFreePort(new TryPort() {
-            
-            @Override
-            public void tryPort(int port) throws Exception {
-                startServer(port);
-            }
-        });
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        server.stop();
-        server.join();
-    }
-
-    @AfterClass
-    public static void tearDownOnce() throws Exception {
-
-        Spawn storage = spawnThermostat("storage", "--stop");
-        storage.expect("server shutdown complete");
-        storage.expectClose();
-
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
-        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 void startServer(int port) throws Exception {
         final CountDownLatch contextStartedLatch = new CountDownLatch(1);
@@ -185,26 +314,55 @@
         }
     }
 
-    private static void connectStorage(String username, String password) {
-        String url = "http://localhost:" + port + "/thermostat/storage";
-        StartupConfiguration config = new ConnectionConfiguration(url, username, password);
-        webStorage = new WebStorage(config);
-        webStorage.setAgentId(new UUID(42, 24));
-        webStorage.getConnection().connect();
+    private static void addCpuData(int numberOfItems) throws IOException {
+        String[] roleNames = new String[] {
+                Roles.REGISTER_CATEGORY,
+                Roles.ACCESS_REALM,
+                Roles.LOGIN,
+                Roles.APPEND
+        };
+        Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames);
+        storage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        for (int i = 0; i < numberOfItems; i++) {
+            CpuStat pojo = new CpuStat(i, new double[] {i, i*2});
+            pojo.setAgentId("test-agent-id");
+            Add add = storage.createAdd(CpuStatDAO.cpuStatCategory);
+            add.setPojo(pojo);
+            add.apply();
+        }
+
+        storage.getConnection().disconnect();
     }
 
-    private void setupJAASForUser(String[] roleNames, String testuser,
-            String password) throws IOException {
-        Properties userProps = new Properties();
-        userProps.put(testuser, password);
-        Properties roleProps = new Properties();
-        StringBuffer roles = new StringBuffer();
-        for (int i = 0; i < roleNames.length - 1; i++) {
-            roles.append(roleNames[i] + ", ");
+    private static void deleteCpuData() 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(CpuStatDAO.cpuStatCategory);
+
+        storage.purge("test-agent-id");
+
+        storage.getConnection().disconnect();
+    }
+
+    private void executeAndVerifyQuery(Query<CpuStat> query, List<Long> expectedTimestamps) {
+        Cursor<CpuStat> cursor = query.execute();
+
+        for (Long time : expectedTimestamps) {
+            assertTrue(cursor.hasNext());
+            CpuStat pojo = cursor.next();
+            assertEquals("test-agent-id", pojo.getAgentId());
+            assertEquals(time.longValue(), pojo.getTimeStamp());
+            double[] data = pojo.getPerProcessorUsage();
+            assertEquals(time, data[0], EQUALS_DELTA);
+            assertEquals(time*2, data[1], EQUALS_DELTA);
         }
-        roles.append(roleNames[roleNames.length - 1]);
-        roleProps.put(testuser, roles.toString());
-        writeThermostatUsersRolesFile(userProps, roleProps);
+        assertFalse(cursor.hasNext());
     }
 
     @Test
@@ -215,11 +373,7 @@
                 Roles.LOGIN,
                 Roles.APPEND
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        
-        connectStorage(testuser, password);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
         
         Add add = webStorage.createAdd(VmClassStatDAO.vmClassStatsCategory);
@@ -249,341 +403,273 @@
         pojo.setVmId(321);
         add.setPojo(pojo);
         add.apply();
+
+        webStorage.getConnection().disconnect();
     }
 
     @Test
     public void authorizedQuery() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
         
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        Cursor<VmClassStat> cursor = query.execute();
-        assertTrue(cursor.hasNext());
-        cursor.next();
-        assertTrue(cursor.hasNext());
-        cursor.next();
-        assertTrue(cursor.hasNext());
-        cursor.next();
-        assertFalse(cursor.hasNext());
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(0l, 1l, 2l, 3l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryEqualTo() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.equalTo(Key.VM_ID, 987);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.equalTo(Key.TIMESTAMP, 2l);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat foundPojo = cursor.next();
-        assertEquals("fluff", foundPojo.getAgentId());
-        assertEquals(42, foundPojo.getTimeStamp());
-        assertEquals(987, foundPojo.getVmId());
-        assertEquals(12345, foundPojo.getLoadedClasses());
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(2l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryNotEqualTo() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.notEqualTo(Key.VM_ID, 321);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.notEqualTo(Key.TIMESTAMP, 2l);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result1 = cursor.next();
-        assertTrue(cursor.hasNext());
-        VmClassStat result2 = cursor.next();
-        // Account for arbitrary ordering
-        assertTrue(result1.getVmId() == 654 && result2.getVmId() == 987
-                || result1.getVmId() == 987 && result2.getVmId() == 654);
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(0l, 1l, 3l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryGreaterThan() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.greaterThan(Key.VM_ID, 654);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.greaterThan(Key.TIMESTAMP, 2l);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result = cursor.next();
-        assertEquals(987, result.getVmId());
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(3l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryGreaterThanOrEqualTo() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.greaterThanOrEqualTo(Key.VM_ID, 654);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.greaterThanOrEqualTo(Key.TIMESTAMP, 2l);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result1 = cursor.next();
-        assertTrue(cursor.hasNext());
-        VmClassStat result2 = cursor.next();
-        // Account for arbitrary ordering
-        assertTrue(result1.getVmId() == 654 && result2.getVmId() == 987
-                || result1.getVmId() == 987 && result2.getVmId() == 654);
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(2l, 3l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryLessThan() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.lessThan(Key.VM_ID, 654);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.lessThan(Key.TIMESTAMP, 2l);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result = cursor.next();
-        assertEquals(321, result.getVmId());
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(0l, 1l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryLessThanOrEqualTo() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.lessThanOrEqualTo(Key.VM_ID, 654);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.lessThanOrEqualTo(Key.TIMESTAMP, 2l);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result1 = cursor.next();
-        assertTrue(cursor.hasNext());
-        VmClassStat result2 = cursor.next();
-        // Account for arbitrary ordering
-        assertTrue(result1.getVmId() == 654 && result2.getVmId() == 321
-                || result1.getVmId() == 321 && result2.getVmId() == 654);
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(0l, 1l, 2l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryIn() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.in(Key.VM_ID, new HashSet<>(Arrays.asList(987, 321)), Integer.class);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        List<Long> times = Arrays.asList(0l, 2l);
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.in(Key.TIMESTAMP, new HashSet<>(times), Long.class);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result1 = cursor.next();
-        assertTrue(cursor.hasNext());
-        VmClassStat result2 = cursor.next();
-        // Account for arbitrary ordering
-        assertTrue(result1.getVmId() == 987 && result2.getVmId() == 321
-                || result1.getVmId() == 321 && result2.getVmId() == 987);
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, times);
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryNotIn() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.notIn(Key.VM_ID, new HashSet<>(Arrays.asList(987, 321)), Integer.class);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.notIn(Key.TIMESTAMP, new HashSet<>(Arrays.asList(0l, 2l)), Long.class);
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result = cursor.next();
-        assertEquals(654, result.getVmId());
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(1l, 3l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryNot() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.not(factory.greaterThan(Key.VM_ID, 321));
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.not(factory.greaterThan(Key.TIMESTAMP, 2l));
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result = cursor.next();
-        assertEquals(321, result.getVmId());
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(0l, 1l, 2l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryAnd() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.and(factory.greaterThan(Key.VM_ID, 321), factory.lessThanOrEqualTo(Key.VM_ID, 654));
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.and(factory.greaterThan(Key.TIMESTAMP, 0l),
+                                      factory.lessThan(Key.TIMESTAMP, 2l));
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result = cursor.next();
-        assertEquals(654, result.getVmId());
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(1l));
+
+        webStorage.getConnection().disconnect();
     }
     
     @Test
     public void authorizedQueryOr() throws Exception {
+
         String[] roleNames = new String[] {
                 Roles.REGISTER_CATEGORY,
                 Roles.READ,
                 Roles.LOGIN,
                 Roles.ACCESS_REALM
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
-        webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory);
-        
-        Query<VmClassStat> query = webStorage.createQuery(VmClassStatDAO.vmClassStatsCategory);
-        ExpressionFactory factory = new ExpressionFactory();
-        Expression expr = factory.or(factory.greaterThan(Key.VM_ID, 654), 
-                factory.greaterThanOrEqualTo(VmClassStatDAO.loadedClassesKey, 67890L));
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        webStorage.registerCategory(CpuStatDAO.cpuStatCategory);
+
+        Query<CpuStat> query = webStorage.createQuery(CpuStatDAO.cpuStatCategory);
+        Expression expr = factory.or(factory.greaterThan(Key.TIMESTAMP, 2l),
+                                      factory.lessThan(Key.TIMESTAMP, 1l));
         query.where(expr);
-        Cursor<VmClassStat> cursor = query.execute();
-        
-        assertTrue(cursor.hasNext());
-        VmClassStat result1 = cursor.next();
-        assertTrue(cursor.hasNext());
-        VmClassStat result2 = cursor.next();
-        // Account for arbitrary ordering
-        assertTrue(result1.getVmId() == 987 && result2.getVmId() == 654
-                || result1.getVmId() == 654 && result2.getVmId() == 987);
-        assertFalse(cursor.hasNext());
+        query.sort(Key.TIMESTAMP, SortDirection.ASCENDING);
+
+        executeAndVerifyQuery(query, Arrays.asList(0l, 3l));
+
+        webStorage.getConnection().disconnect();
     }
 
     @Test
@@ -594,10 +680,7 @@
                 Roles.ACCESS_REALM,
                 Roles.LOGIN
         };
-        String testuser = "testuser";
-        String password = "testpassword";
-        setupJAASForUser(roleNames, testuser, password);
-        connectStorage(testuser, password);
+        Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
         
         byte[] data = "Hello World".getBytes();
         webStorage.saveFile("test", new ByteArrayInputStream(data));
@@ -621,43 +704,60 @@
             i = loadStream.read();
         }
         assertEquals("Hello World", str.toString());
+
+        webStorage.getConnection().disconnect();
     }
-    
-    private static class WebAppContextListener implements Listener {
 
-        private Throwable cause;
-        private boolean failed = false;
-        private final CountDownLatch contextStartedLatch;
-        private WebAppContextListener(CountDownLatch latch) {
-            this.contextStartedLatch = latch;
-        }
-        
-        @Override
-        public void lifeCycleStarting(LifeCycle event) {
-            // nothing
-        }
+    @Test
+    public void unauthorizedLogin() throws Exception {
+        String[] roleNames = new String[] {
+                Roles.ACCESS_REALM
+        };
+
+        CountDownLatch statusLatch = new CountDownLatch(1);
+        AtomicBoolean listenerTriggered = new AtomicBoolean(false);
+        ConnectionListener listener = new CountdownConnectionListener(ConnectionStatus.FAILED_TO_CONNECT, statusLatch, listenerTriggered);
+        @SuppressWarnings("unused")
+        Storage storage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames, listener);
+        statusLatch.await();
+        assertTrue(listenerTriggered.get());
+    }
 
-        @Override
-        public void lifeCycleStarted(LifeCycle event) {
-            contextStartedLatch.countDown();
-        }
+    @Test
+    public void setDefaultAgentID() throws Exception {
+        String[] roleNames = new String[] {
+                Roles.ACCESS_REALM,
+                Roles.LOGIN,
+                Roles.REGISTER_CATEGORY,
+                Roles.READ,
+                Roles.APPEND,
+                Roles.PURGE
+        };
+        Storage storage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames);
+        UUID uuid = new UUID(42, 24);
+        storage.setAgentId(uuid);
 
-        @Override
-        public void lifeCycleFailure(LifeCycle event, Throwable cause) {
-            this.failed = true;
-            this.cause = cause;
-            contextStartedLatch.countDown();
-        }
+        storage.registerCategory(VmCpuStatDAO.vmCpuStatCategory);
+        long timeStamp = 5;
+        int vmId = 10;
+        double cpuLoad = 0.15;
+        VmCpuStat pojo = new VmCpuStat(timeStamp, vmId, cpuLoad);
+        // Note: agentId not set on pojo
+        Add add = storage.createAdd(VmCpuStatDAO.vmCpuStatCategory);
+        add.setPojo(pojo);
+        add.apply();
 
-        @Override
-        public void lifeCycleStopping(LifeCycle event) {
-            // nothing
-        }
+        Query<VmCpuStat> query = storage.createQuery(VmCpuStatDAO.vmCpuStatCategory);
+        Cursor<VmCpuStat> cursor = query.execute();
+        assertTrue(cursor.hasNext());
+        pojo = cursor.next();
+        assertFalse(cursor.hasNext());
 
-        @Override
-        public void lifeCycleStopped(LifeCycle event) {
-            // nothing
-        }
-            
+        assertEquals(timeStamp, pojo.getTimeStamp());
+        assertEquals(vmId, pojo.getVmId());
+        assertEquals(cpuLoad, pojo.getCpuLoad(), EQUALS_DELTA);
+        assertEquals(uuid.toString(), pojo.getAgentId());
+
+        storage.purge(uuid.toString());
     }
 }