@Test
  public void testTXAndQueries() throws CacheException, QueryException {
    IndexManager.TEST_RANGEINDEX_ONLY = true;
    try {
      final QueryService qs = cache.getQueryService();

      final String fromClause = region.getFullPath() + " value ";
      final String qstr = "SELECT DISTINCT * FROM " + fromClause;

      // Create a region with async index updates
      AttributesFactory af = new AttributesFactory(region.getAttributes());
      af.setIndexMaintenanceSynchronous(false);
      final Region aIregion = cache.createRegion(getUniqueName(), af.create());
      final String aIfromClause = aIregion.getFullPath() + " value ";
      final String aIqstr = "SELECT DISTINCT * FROM " + aIfromClause;

      // Confirm base functionality for query results
      region.put("qkey0", "qval0");
      region.put("qkey1", "qval01");
      Query q = qs.newQuery(qstr);
      SelectResults res = (SelectResults) q.execute();
      assertEquals(2, res.size());
      String val;
      for (final Object item : res) {
        val = (String) item;
        assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval"));
      }
      q = qs.newQuery(qstr + " where value.length > 6");
      res = (SelectResults) q.execute();
      assertEquals(0, res.size());

      aIregion.put("qkey0", "qval0");
      aIregion.put("qkey1", "qval01");
      q = qs.newQuery(aIqstr);
      res = (SelectResults) q.execute();
      assertEquals(2, res.size());
      for (final Object value : res) {
        val = (String) value;
        assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval"));
      }
      q = qs.newQuery(qstr + " where value.length > 6");
      res = (SelectResults) q.execute();
      assertEquals(0, res.size());

      // Test query results in a transaction
      txMgr.begin();
      Query q1 = qs.newQuery(qstr);
      region.put("noQkey2", "noQval2");
      res = (SelectResults) q1.execute();
      assertEquals(2, res.size());
      for (final Object o : res) {
        val = (String) o;
        assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval"));
      }
      Query aIq1 = qs.newQuery(aIqstr);
      aIregion.put("noQkey2", "noQval2");
      res = (SelectResults) aIq1.execute();
      assertEquals(2, res.size());
      for (final Object re : res) {
        val = (String) re;
        assertTrue("Value: " + val + " does not start with qval", val.startsWith("qval"));
      }
      Query q2 = qs.newQuery(qstr + " where value.length > 6");
      res = (SelectResults) q2.execute();
      assertEquals(0, res.size());
      Query aIq2 = qs.newQuery(aIqstr + " where value.length > 6");
      res = (SelectResults) aIq2.execute();
      assertEquals(0, res.size());
      txMgr.commit();
      res = (SelectResults) q1.execute();
      assertEquals(3, res.size());
      res = (SelectResults) q2.execute();
      assertEquals(1, res.size());
      res = (SelectResults) aIq1.execute();
      assertEquals(3, res.size());
      res = (SelectResults) aIq2.execute();
      assertEquals(1, res.size());

      region.destroy("noQkey2");
      aIregion.destroy("noQkey2");

      // Confirm base functionality for index creation
      Index index0 = qs.createIndex("TXIndex0", IndexType.FUNCTIONAL, "value.length", fromClause);
      assertEquals(2, index0.getStatistics().getNumberOfKeys());
      assertEquals(2, index0.getStatistics().getNumberOfValues());
      assertEquals(2, index0.getStatistics().getNumUpdates()); // Shouldn't this be zero?
      Index aIindex0 =
          qs.createIndex("aITXIndex0", IndexType.FUNCTIONAL, "value.length", aIfromClause);
      assertEquals(2, aIindex0.getStatistics().getNumberOfKeys());
      assertEquals(2, aIindex0.getStatistics().getNumberOfValues());
      assertEquals(2, aIindex0.getStatistics().getNumUpdates()); // Shouldn't this be zero?
      q = qs.newQuery(qstr);
      res = (SelectResults) q.execute();
      assertEquals(2, res.size());
      assertEquals(0, index0.getStatistics().getTotalUses());
      aIq1 = qs.newQuery(aIqstr);
      res = (SelectResults) aIq1.execute();
      assertEquals(2, res.size());
      assertEquals(0, aIindex0.getStatistics().getTotalUses());

      final String val2 = "qval000002";
      region.put("qkey2", val2);
      assertEquals(3, index0.getStatistics().getNumUpdates()); // Shouldn't this be 1?
      assertEquals(3, index0.getStatistics().getNumberOfKeys());
      assertEquals(3, index0.getStatistics().getNumberOfValues());
      aIregion.put("qkey2", val2);
      final IndexManager.IndexUpdaterThread upThread =
          ((AbstractRegion) aIregion).getIndexManager().getUpdaterThread();
      while (!upThread.isDone()) {
        pause(20);
      }
      // @todo asif: for some reason the value returned by getNumberOfKeys is unstable.
      // Even when the code waits for it to be the expected value it intermittently
      // will fail because it never gets to be the expected value.
      // This stat (in RangeIndex at least) is only updated when we add a new key
      // to the valueToEntriesMap. I do not see a place that we ever remove from
      // this map (even when we do a removeMapping).
      waitForUpdates(aIindex0, 3);
      waitForKeys(aIindex0, 3);
      assertEquals(3, aIindex0.getStatistics().getNumUpdates()); // Shouldn't this be 1?
      assertEquals(3, aIindex0.getStatistics().getNumberOfKeys());
      assertEquals(3, aIindex0.getStatistics().getNumberOfValues());
      q = qs.newQuery("ELEMENT(" + qstr + " where value.length > 6)");
      assertEquals(val2, q.execute());
      assertEquals(1, index0.getStatistics().getTotalUses());
      aIq1 = qs.newQuery("ELEMENT(" + aIqstr + " where value.length > 6)");
      assertEquals(val2, aIq1.execute());

      region.destroy("qkey2");
      waitForKeys(index0, 2);
      assertEquals(2, index0.getStatistics().getNumberOfKeys()); // Shouldn't this be 1, again?
      assertEquals(2, index0.getStatistics().getNumberOfValues());
      assertEquals(4, index0.getStatistics().getNumUpdates());
      aIregion.destroy("qkey2");
      while (!upThread.isDone()) {
        pause(20);
      }
      waitForUpdates(aIindex0, 4);
      // waitForKeys(aIindex0, 3);
      // assertIndexDetailsEquals(3, aIindex0.getStatistics().getNumberOfKeys()); // Shouldn't this
      // be 1, again?
      assertEquals(2, aIindex0.getStatistics().getNumberOfValues());
      assertEquals(4, aIindex0.getStatistics().getNumUpdates());

      // Test index creation
      txMgr.begin();
      region.destroy("qkey1");
      region.put("noQkey3", "noQval3");
      Index index1 = qs.createIndex("TXIndex1", IndexType.FUNCTIONAL, "value", fromClause);
      assertEquals(2, index1.getStatistics().getNumberOfKeys());
      assertEquals(2, index1.getStatistics().getNumberOfValues());
      assertEquals(2, index1.getStatistics().getNumUpdates());
      assertEquals(2, index0.getStatistics().getNumberOfKeys());
      assertEquals(2, index0.getStatistics().getNumberOfValues());
      assertEquals(4, index0.getStatistics().getNumUpdates());

      aIregion.destroy("qkey1");
      aIregion.put("noQkey3", "noQval3");
      Index aIindex1 = qs.createIndex("aITXIndex1", IndexType.FUNCTIONAL, "value", aIfromClause);
      while (!upThread.isDone()) {
        pause(20);
      }
      waitForUpdates(aIindex0, 4);
      waitForUpdates(aIindex1, 2);
      // waitForKeys(aIindex0, 3);
      // waitForKeys(aIindex1, 2);
      assertEquals(2, aIindex1.getStatistics().getNumberOfKeys());
      assertEquals(2, aIindex1.getStatistics().getNumberOfValues());
      assertEquals(2, aIindex1.getStatistics().getNumUpdates());
      // assertIndexDetailsEquals(3, aIindex0.getStatistics().getNumberOfKeys());
      assertEquals(2, aIindex0.getStatistics().getNumberOfValues());
      assertEquals(4, aIindex0.getStatistics().getNumUpdates());


      q = qs.newQuery(qstr);
      res = (SelectResults) q.execute();
      assertEquals(2, res.size());
      assertEquals(0, index1.getStatistics().getTotalUses());
      assertEquals(1, index0.getStatistics().getTotalUses());

      aIq1 = qs.newQuery(aIqstr);
      res = (SelectResults) aIq1.execute();
      assertEquals(2, res.size());
      assertEquals(0, aIindex1.getStatistics().getTotalUses());
      assertEquals(1, aIindex0.getStatistics().getTotalUses());

      q = qs.newQuery(qstr + " where value < 'q'");
      res = (SelectResults) q.execute();
      assertEquals(1, index1.getStatistics().getTotalUses());
      assertEquals(0, res.size());

      aIq1 = qs.newQuery(aIqstr + " where value < 'q'");
      res = (SelectResults) aIq1.execute();
      assertEquals(1, aIindex1.getStatistics().getTotalUses());
      assertEquals(0, res.size());

      region.put("noQkey4", "noQval4");
      assertEquals(2, index1.getStatistics().getNumberOfKeys());
      assertEquals(2, index1.getStatistics().getNumberOfValues());
      assertEquals(2, index1.getStatistics().getNumUpdates());
      assertEquals(2, index0.getStatistics().getNumberOfKeys());
      assertEquals(2, index0.getStatistics().getNumberOfValues());
      assertEquals(4, index0.getStatistics().getNumUpdates());

      aIregion.put("noQkey4", "noQval4");
      while (!upThread.isDone()) {
        pause(20);
      }
      waitForUpdates(aIindex0, 4);
      waitForUpdates(aIindex1, 2);
      waitForKeys(aIindex0, 2);
      // waitForKeys(aIindex1, 2);
      // assertIndexDetailsEquals(2, aIindex1.getStatistics().getNumberOfKeys());
      assertEquals(2, aIindex1.getStatistics().getNumberOfValues());
      assertEquals(2, aIindex1.getStatistics().getNumUpdates());
      assertEquals(2, aIindex0.getStatistics().getNumberOfKeys());
      assertEquals(2, aIindex0.getStatistics().getNumberOfValues());
      assertEquals(4, aIindex0.getStatistics().getNumUpdates());

      q = qs.newQuery(qstr + " where value < 'q'");
      res = (SelectResults) q.execute();
      assertEquals(2, index1.getStatistics().getTotalUses());
      assertEquals(0, res.size());

      aIq1 = qs.newQuery(aIqstr + " where value <'q'");
      res = (SelectResults) aIq1.execute();
      assertEquals(2, aIindex1.getStatistics().getTotalUses());
      assertEquals(0, res.size());

      q = qs.newQuery(qstr + " where value.length > 6");
      res = (SelectResults) q.execute();
      assertEquals(2, index0.getStatistics().getTotalUses());
      assertEquals(0, res.size());

      aIq1 = qs.newQuery(aIqstr + " where value.length > 6");
      res = (SelectResults) aIq1.execute();
      assertEquals(2, aIindex0.getStatistics().getTotalUses());
      assertEquals(0, res.size());

      txMgr.commit();
      assertEquals(3, index1.getStatistics().getNumberOfKeys());
      assertEquals(3, index1.getStatistics().getNumberOfValues()); // Shouldn't this be 4?
      assertEquals(5, index1.getStatistics().getNumUpdates());
      assertEquals(2, index0.getStatistics().getNumberOfKeys());
      assertEquals(3, index0.getStatistics().getNumberOfValues()); // Shouldn't this be 4?
      assertEquals(7, index0.getStatistics().getNumUpdates());

      while (!upThread.isDone()) {
        pause(20);
      }
      waitForUpdates(aIindex0, 7);
      waitForUpdates(aIindex1, 5);
      // waitForKeys(aIindex0, 4); // sometimes 3 sometimes 4
      // waitForKeys(aIindex1, 3);
      assertEquals(3, aIindex1.getStatistics().getNumberOfKeys());
      assertEquals(3, aIindex1.getStatistics().getNumberOfValues()); // Shouldn't this be 4?
      assertEquals(5, aIindex1.getStatistics().getNumUpdates());
      // assertIndexDetailsEquals(4, aIindex0.getStatistics().getNumberOfKeys());
      assertEquals(3, aIindex0.getStatistics().getNumberOfValues()); // Shouldn't this be 4?
      assertEquals(7, aIindex0.getStatistics().getNumUpdates());

      q = qs.newQuery(qstr + " where value <'q'");
      res = (SelectResults) q.execute();
      assertEquals(3, index1.getStatistics().getTotalUses());
      assertEquals(2, res.size());

      aIq1 = qs.newQuery(aIqstr + " where value < 'q'");
      res = (SelectResults) aIq1.execute();
      assertEquals(3, aIindex1.getStatistics().getTotalUses());
      assertEquals(2, res.size());

      q = qs.newQuery(qstr + " where value.length > 6");
      res = (SelectResults) q.execute();
      assertEquals(3, index0.getStatistics().getTotalUses());
      assertEquals(2, res.size());

      aIq1 = qs.newQuery(aIqstr + " where value.length > 6");
      res = (SelectResults) aIq1.execute();
      assertEquals(3, aIindex0.getStatistics().getTotalUses());
      assertEquals(2, res.size());
    } finally {
      IndexManager.TEST_RANGEINDEX_ONLY = false;
    }
  }
Test to make sure CacheListener callbacks are called in place with the CacheEvents properly
constructed
geode-core/src/integrationTest/java/org/apache/geode/TXJUnitTest.java