changeset 1192:56e89524791c

Merge
author Andriy Petrus <apetrus@redhat.com>
date Wed, 31 Jul 2013 15:30:51 -0400
parents 40e2c7a18bda (current diff) e7bdfcace2b0 (diff)
children 1925258e6309
files
diffstat 12 files changed, 263 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/CliTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/CliTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -45,7 +45,6 @@
 import org.junit.Test;
 
 import expectj.Spawn;
-import expectj.TimeoutException;
 
 /**
  * Integration tests to exercise the basics of the thermostat command line.
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -132,6 +132,39 @@
     public static Spawn spawnThermostat(String... args) throws IOException {
         return spawnThermostat(false, args);
     }
+    
+    public static Spawn startStorage() throws Exception {
+        clearStorageDataDirectory();
+
+        Spawn storage = spawnThermostat("storage", "--start");
+        try {
+            storage.expect("pid:");
+        } catch (IOException e) {
+            // this may happen if storage is already running.
+            e.printStackTrace();
+            String stdOutContents = storage.getCurrentStandardOutContents();
+            
+            System.err.flush();
+            System.out.flush();
+            System.err.println("stdout was: -->" + stdOutContents +"<--");
+            System.err.println("stderr was: -->" + storage.getCurrentStandardErrContents() + "<--");
+            System.err.flush();
+            assertFalse(stdOutContents.contains("Storage is already running with pid"));
+            throw new Exception("Something funny is going on when trying to start storage!", e);
+        }
+        storage.expectClose();
+
+        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+        return storage;
+    }
+    
+    public static Spawn stopStorage() throws Exception {
+        Spawn storage = spawnThermostat("storage", "--stop");
+        storage.expect("server shutdown complete");
+        storage.expectClose();
+        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+        return storage;
+    }
 
     public static Spawn spawnThermostat(boolean localeDependent, String... args) throws IOException {
         ExpectJ expect = new ExpectJ(TIMEOUT_IN_SECONDS);
@@ -213,6 +246,7 @@
     }
 
     private static void killProcess(int processId) throws Exception {
+        System.err.println("Killing process with pid: " + processId);
         Runtime.getRuntime().exec("kill " + processId).waitFor();
     }
 
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/MongoQueriesTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -72,8 +72,6 @@
 import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO;
 import com.redhat.thermostat.vm.cpu.common.model.VmCpuStat;
 
-import expectj.Spawn;
-
 /*
  * This test class starts up a mongod instance and tests if thermostat
  * queries with expressions return what they supposed to return. 
@@ -117,13 +115,7 @@
 
     @BeforeClass
     public static void setUpOnce() throws Exception {
-        clearStorageDataDirectory();
-
-        Spawn storage = spawnThermostat("storage", "--start");
-        storage.expect("pid:");
-        storage.expectClose();
-
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+        startStorage();
 
         addCpuData(4);
     }
@@ -132,11 +124,7 @@
     public static void tearDownOnce() throws Exception {
         deleteCpuData();
 
-        Spawn storage = spawnThermostat("storage", "--stop");
-        storage.expect("server shutdown complete");
-        storage.expectClose();
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
-
+        stopStorage();
     }
 
     /*
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -74,7 +74,6 @@
         shell.expectClose();
 
         String stdOut = shell.getCurrentStandardOutContents();
-        String stdErr = shell.getCurrentStandardErrContents();
 
         assertTrue(stdOut.contains("list of commands"));
         assertTrue(stdOut.contains("help"));
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -38,8 +38,6 @@
 
 import java.io.IOException;
 
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -49,22 +47,14 @@
 
 public class StorageConnectionTest extends IntegrationTest {
 
-    @BeforeClass
-    public static void setUpOnce() throws IOException, TimeoutException, ExpectJException {
-        Spawn storage = spawnThermostat("storage", "--start");
-        storage.expect("pid:");
-        storage.expectClose();
-
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+    // @BeforeClass // reinstate once we actually need storage running (see ignored tests)
+    public static void setUpOnce() throws Exception {
+        startStorage();
     }
 
-    @AfterClass
-    public static void tearDownOnce() throws IOException, TimeoutException, ExpectJException {
-        Spawn storage = spawnThermostat("storage", "--stop");
-        storage.expect("server shutdown complete");
-        storage.expectClose();
-
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+    // @AfterClass // reinstate once we actually need storage running
+    public static void tearDownOnce() throws Exception {
+        stopStorage();
     }
 
     @Ignore //FIXME when keyring/preferences improvements have been made, un-Ignore
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -46,11 +46,7 @@
     public void startAndStopStorage() throws Exception {
         Spawn storage;
 
-        storage = spawnThermostat("storage", "--start");
-        storage.expect("pid:");
-        storage.expectClose();
-
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+        storage = startStorage();
 
         storage = spawnThermostat("storage", "--status");
         storage.expect("Storage is running");
@@ -58,11 +54,7 @@
         
         assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
         
-        storage = spawnThermostat("storage", "--stop");
-        storage.expect("server shutdown complete");
-        storage.expectClose();
-        
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
+        storage = stopStorage();
         
         storage = spawnThermostat("storage", "--status");
         storage.expect("Storage is not running");
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -52,19 +52,15 @@
 public class VmCommandsTest extends IntegrationTest {
 
     @BeforeClass
-    public static void setUpOnce() throws IOException, InterruptedException {
-        clearStorageDataDirectory();
-
-        Process startStorage = runThermostat("storage", "--start");
-        startStorage.waitFor();
+    public static void setUpOnce() throws Exception {
+        startStorage();
 
         // TODO insert actual data into the database and test that
     }
 
     @AfterClass
-    public static void tearDownOnce() throws InterruptedException, IOException {
-        Process stopStorage = runThermostat("storage", "--stop");
-        stopStorage.waitFor();
+    public static void tearDownOnce() throws Exception {
+        stopStorage();
     }
 
     @Ignore //FIXME when keyring/preferences improvements have been made, un-Ignore
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -93,8 +93,6 @@
 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
@@ -230,13 +228,8 @@
 
     @BeforeClass
     public static void setUpOnce() throws Exception {
-        clearStorageDataDirectory();
+        startStorage();
 
-        Spawn storage = spawnThermostat("storage", "--start");
-        storage.expect("pid:");
-        storage.expectClose();
-
-        assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents());
         backupUsers = Files.createTempFile("itest-backup-thermostat-users", "");
         backupRoles = Files.createTempFile("itest-backup-thermostat-roles", "");
         backupRoles.toFile().deleteOnExit();
@@ -261,13 +254,10 @@
     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();
+        
+        stopStorage();
 
         Files.copy(backupUsers, new File(THERMOSTAT_USERS_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
         Files.copy(backupRoles, new File(THERMOSTAT_ROLES_FILE).toPath(), StandardCopyOption.REPLACE_EXISTING);
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostRef.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/HostRef.java	Wed Jul 31 15:30:51 2013 -0400
@@ -36,11 +36,20 @@
 
 package com.redhat.thermostat.storage.core;
 
+/**
+ * Identifies an agent or a host
+ */
+// See http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=1508 for
+// more information
 public class HostRef implements Ref {
 
     private final String uid;
     private final String name;
 
+    /**
+     * @param id the UUID string that uniquely identifies an agent/host
+     * @param name the host name of an agent/host
+     */
     public HostRef(String id, String name) {
         this.uid = id;
         this.name = name;
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java	Wed Jul 31 15:30:51 2013 -0400
@@ -45,6 +45,9 @@
 import com.redhat.thermostat.storage.core.Key;
 import com.redhat.thermostat.storage.model.AgentInformation;
 
+/**
+ * Access information about agents that agents publish to storage.
+ */
 @Service
 public interface AgentInfoDAO extends Countable {
 
@@ -60,17 +63,47 @@
             ALIVE_KEY,
             CONFIG_LISTEN_ADDRESS);
 
+    /**
+     * Get information about all known agents.
+     *
+     * @return a {@link List} of {@link AgentInformation} for all agents
+     * who have published their information. Will be empty if there is no
+     * information.
+     */
     List<AgentInformation> getAllAgentInformation();
 
+    /**
+     * Get information about all alive agents.
+     *
+     * @return a {@link List} of {@link AgentInformation} for all alive
+     * agents who have published their information. Will be empty if there
+     * is no information or no alive agents.
+     */
     List<AgentInformation> getAliveAgents();
 
+    /**
+     * Get information about a specific agent.
+     *
+     * @return a {@link AgentInformation} describing information about the agent
+     * indicated by {@code agentRef}. {@code null} if no information about the
+     * agent could be located.
+     */
     AgentInformation getAgentInformation(HostRef agentRef);
 
+    /**
+     * Publish information about agent into the storage.
+     */
     void addAgentInformation(AgentInformation agentInfo);
 
+    /**
+     * Update information about an existing agent. No changes will be performed
+     * if there is no matching agent.
+     */
     void updateAgentInformation(AgentInformation agentInfo);
 
+    /**
+     * Remove information about an agent that was published to storage.
+     */
     void removeAgentInformation(AgentInformation agentInfo);
 
 }
-
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParser.java	Wed Jul 31 15:30:51 2013 -0400
@@ -428,17 +428,26 @@
             String stringTerm = getStringTerm(term);
             return stringTerm;
         } catch (DescriptorParsingException e) {
-            // must be int or boolean
+            // Must be integer (long/int) or boolean. First check for boolean,
+            // then for long and regular ints.
+            if (term.equals(Boolean.toString(false)) || term.equals(Boolean.toString(true))) {
+                boolean boolVal = Boolean.parseBoolean(term);
+                return boolVal;
+            }
+            // Next, parse long or int.
             try {
+                int lastCharInTokenIndex = term.length() - 1;
+                // preceding l/L indicate long integer types.
+                if (term.charAt(lastCharInTokenIndex) == 'L' || term.charAt(lastCharInTokenIndex) == 'l') {
+                    long longVal = Long.parseLong(term.substring(0, lastCharInTokenIndex));
+                    return longVal;
+                }
+                // must be integer or some invalid type
                 int intVal = Integer.parseInt(term);
                 return intVal;
             } catch (NumberFormatException nfe) {
-                if (term.equals(Boolean.toString(false)) || term.equals(Boolean.toString(true))) {
-                    boolean boolVal = Boolean.parseBoolean(term);
-                    return boolVal;
-                } else {
-                    throw new DescriptorParsingException("Illegal terminal type. Token was ->" + term + "<-");
-                }
+                String msg = "Illegal terminal type. Token was ->" + term + "<-";
+                throw new DescriptorParsingException(msg);
             }
         }
     }
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java	Wed Jul 31 15:10:25 2013 -0400
+++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/statement/StatementDescriptorParserTest.java	Wed Jul 31 15:30:51 2013 -0400
@@ -110,6 +110,134 @@
     }
     
     @Test
+    public void testParseLongInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000000003L";
+        doTestType(descrString, 30000000003L, 0);
+    }
+    
+    @Test
+    public void testParseLongInWhere2() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000000003l";
+        doTestType(descrString, 30000000003L, 0);
+    }
+    
+    @Test
+    public void testParseLongInWhere3() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 3l";
+        doTestType(descrString, 3L, 0);
+    }
+    
+    @Test
+    public void testParseLongInWhere4() throws DescriptorParsingException {
+        long val = Long.MIN_VALUE;
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != " + val + "l";
+        doTestType(descrString, val, 0);
+    }
+    
+    @Test
+    public void testParseIntInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000";
+        doTestType(descrString, 30000, 0);
+    }
+    
+    @Test
+    public void testParseIntInWhere2() throws DescriptorParsingException {
+        int val = Integer.MAX_VALUE - 1;
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != " + val;
+        doTestType(descrString, val, 0);
+    }
+    
+    @Test
+    public void testParseIntInWhere3() throws DescriptorParsingException {
+        int val = Integer.MIN_VALUE;
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != " + val;
+        doTestType(descrString, val, 0);
+    }
+    
+    @Test
+    public void testParseBooleanInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != true";
+        doTestType(descrString, true, 0);
+    }
+    
+    @Test
+    public void testParseBooleanInWhere2() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != false";
+        doTestType(descrString, false, 0);
+    }
+    
+    @Test
+    public void testParseStringInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 'testing'";
+        doTestType(descrString, "testing", 0);
+    }
+    
+    @Test
+    public void testParseStringTypeFreeVarInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?s";
+        UnfinishedValueNode unfinished = new UnfinishedValueNode();
+        unfinished.setLHS(false);
+        unfinished.setType(String.class);
+        unfinished.setParameterIndex(0);
+        doTestType(descrString, unfinished, 1);
+    }
+    
+    @Test
+    public void testParseIntTypeFreeVarInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?i";
+        UnfinishedValueNode unfinished = new UnfinishedValueNode();
+        unfinished.setLHS(false);
+        unfinished.setType(Integer.class);
+        unfinished.setParameterIndex(0);
+        doTestType(descrString, unfinished, 1);
+    }
+    
+    @Test
+    public void testParseLongTypeFreeVarInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?l";
+        UnfinishedValueNode unfinished = new UnfinishedValueNode();
+        unfinished.setLHS(false);
+        unfinished.setType(Long.class);
+        unfinished.setParameterIndex(0);
+        doTestType(descrString, unfinished, 1);
+    }
+    
+    @Test
+    public void testParseBooleanTypeFreeVarInWhere() throws DescriptorParsingException {
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != ?b";
+        UnfinishedValueNode unfinished = new UnfinishedValueNode();
+        unfinished.setLHS(false);
+        unfinished.setType(Boolean.class);
+        unfinished.setParameterIndex(0);
+        doTestType(descrString, unfinished, 1);
+    }
+    
+    private void doTestType(String strDesc, Object bVal, int expNumFreeVars) throws DescriptorParsingException {
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        ParsedStatementImpl<AgentInformation> statement = (ParsedStatementImpl<AgentInformation>)parser.parse();
+        assertEquals(expNumFreeVars, statement.getNumParams());
+        assertEquals(mockQuery.getClass().getName(), statement.getRawStatement().getClass().getName());
+        SuffixExpression tree = statement.getSuffixExpression();
+        assertNull(tree.getLimitExpn());
+        assertNull(tree.getSortExpn());
+        assertNotNull(tree.getWhereExpn());
+        
+        WhereExpression expected = new WhereExpression();
+        BinaryExpressionNode notEquals = new BinaryExpressionNode(expected.getRoot());
+        expected.getRoot().setValue(notEquals);
+        notEquals.setOperator(BinaryComparisonOperator.NOT_EQUAL_TO);
+        TerminalNode a = new TerminalNode(notEquals);
+        a.setValue(new Key<String>("a", false));
+        TerminalNode b = new TerminalNode(notEquals);
+        b.setValue(bVal);
+        notEquals.setLeftChild(a);
+        notEquals.setRightChild(b);
+        
+        assertTrue(WhereExpressions.equals(expected, tree.getWhereExpn()));
+    }
+    
+    @Test
     public void testParseNotEqualComparisonInWhere() throws DescriptorParsingException {
         String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 'b'";
         StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
@@ -1109,12 +1237,29 @@
     }
     
     @Test
+    public void rejectLongValAsIntType() throws DescriptorParsingException {
+        // 30000000003 > Integer.MAX_VALUE; needs to be preceded by 'l/L'
+        String descrString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " WHERE 'a' != 30000000003";
+        StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descrString);
+        parser = new StatementDescriptorParser<>(storage, desc);
+        
+        try {
+            parser.parse();
+            fail("should not parse");
+        } catch (DescriptorParsingException e) {
+            // pass
+            assertTrue(e.getMessage().contains("Illegal terminal type."));
+        }
+    }
+
+    @Test
     public void rejectLimitWhichIsNotInt() {
         String descString = "QUERY " + AgentInfoDAO.CATEGORY.getName() + " LIMIT illegal";
         StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, descString);
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             assertEquals("Invalid limit expression. 'illegal' not an integer", e.getMessage());
         }
@@ -1127,6 +1272,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
             assertTrue(e.getMessage().contains("Expected string value. Got term ->a<-"));
@@ -1141,6 +1287,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
             assertEquals("Unknown type of free parameter: '?'", e.getMessage());
@@ -1154,6 +1301,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
             assertTrue(e.getMessage().contains("Expected ASC or DSC"));
@@ -1167,6 +1315,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
         }
@@ -1181,6 +1330,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
         }
@@ -1194,6 +1344,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
         }
@@ -1207,6 +1358,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
         }
@@ -1220,6 +1372,7 @@
         parser = new StatementDescriptorParser<>(storage, desc);
         try {
             parser.parse();
+            fail("should not parse");
         } catch (DescriptorParsingException e) {
             // pass
         }