@Test
  public void shouldNotifyUserWhenEmailAddressesAreDifferent() {
    driver.get(URL);
    String title = driver.getTitle();
    assertEquals("Rule Financial Registration Form", title);

    int randomIntNUmberForRegistration = this.generator.nextInt(100000);

    driver.findElement(By.name("firstName")).clear();
    driver.findElement(By.name("firstName")).sendKeys("Marcin");
    driver.findElement(By.name("lastName")).clear();
    driver.findElement(By.name("lastName")).sendKeys("Kowalczyk");

    String email = new String("marcinkowalczyk" + randomIntNUmberForRegistration + "@gmail.com");

    driver.findElement(By.name("email")).clear();
    driver.findElement(By.name("email")).sendKeys(email);
    driver.findElement(By.name("repeatEmail")).clear();
    driver.findElement(By.name("repeatEmail")).sendKeys("wrong" + email);

    WebElement divErrorEmailAdress =
        driver.findElement(By.xpath("html/body/div[2]/div[2]/div/div/div/div[5]/div/div"));
    boolean ariaHidden = Boolean.getBoolean(divErrorEmailAdress.getAttribute("aria-hidden"));
    assertEquals(ariaHidden, false);
  }
 @Before
 public void setUp() {
   if (!Boolean.parseBoolean(System.getProperty("test.solr.verbose"))) {
     java.util.logging.Logger.getLogger("org.apache.solr")
         .setLevel(java.util.logging.Level.SEVERE);
     Utils.setLog4jLogLevel(org.apache.log4j.Level.WARN);
   }
   testDataParentPath = System.getProperty("test.data.path");
   testConfigFname = System.getProperty("test.config.file");
   // System.out.println("-----testDataParentPath = "+testDataParentPath);
 }
Beispiel #3
0
@Ignore("Long running test")
public class RemoteSubscriptionModelPerformanceTest {

  // TODO DS test having the server side on another machine
  private static final int _noOfPuts = 50;
  private static final int _noOfRunsToAverage =
      Boolean.parseBoolean(System.getProperty("quick", "true")) ? 2 : 100;
  private static final long _secondInNanos = 1_000_000_000L;
  private static final AtomicInteger counter = new AtomicInteger();
  private static String _twoMbTestString;
  private static int _twoMbTestStringLength;
  private static Map<String, String> _testMap;
  private static VanillaAssetTree serverAssetTree, clientAssetTree;
  private static ServerEndpoint serverEndpoint;

  private final String _mapName = "PerfTestMap" + counter.incrementAndGet();

  @BeforeClass
  public static void setUpBeforeClass() throws IOException, URISyntaxException {
    //        YamlLogging.showServerReads = true;
    //        YamlLogging.clientReads = true;

    char[] chars = new char[2 << 20];
    Arrays.fill(chars, '~');
    _twoMbTestString = new String(chars);
    _twoMbTestStringLength = _twoMbTestString.length();

    serverAssetTree = new VanillaAssetTree(1).forTesting();
    // The following line doesn't add anything and breaks subscriptions
    serverAssetTree
        .root()
        .addWrappingRule(
            MapView.class,
            "map directly to KeyValueStore",
            VanillaMapView::new,
            KeyValueStore.class);
    serverAssetTree
        .root()
        .addLeafRule(
            KeyValueStore.class,
            "use Chronicle Map",
            (context, asset) ->
                new ChronicleMapKeyValueStore(
                    context
                        .basePath(OS.TARGET)
                        .entries(_noOfPuts)
                        .averageValueSize(_twoMbTestStringLength),
                    asset));
    TCPRegistry.createServerSocketChannelFor("RemoteSubscriptionModelPerformanceTest.port");
    serverEndpoint =
        new ServerEndpoint(
            "RemoteSubscriptionModelPerformanceTest.port", serverAssetTree, WireType.BINARY);

    clientAssetTree =
        new VanillaAssetTree(13)
            .forRemoteAccess("RemoteSubscriptionModelPerformanceTest.port", WireType.BINARY);
  }

  @AfterClass
  public static void tearDownAfterClass() throws IOException {
    clientAssetTree.close();
    serverEndpoint.close();
    serverAssetTree.close();
    TcpChannelHub.closeAllHubs();
    TCPRegistry.reset();
  }

  @Before
  public void setUp() throws IOException {
    Files.deleteIfExists(Paths.get(OS.TARGET, _mapName));

    _testMap =
        clientAssetTree.acquireMap(_mapName + "?putReturnsNull=true", String.class, String.class);

    _testMap.clear();
  }

  @After
  public void tearDown() throws IOException {
    //        System.out.println("Native memory used "+OS.memory().nativeMemoryUsed());
    //        System.gc();

  }

  /**
   * Test that listening to events for a given key can handle 50 updates per second of 2 MB string
   * values.
   */
  @Test
  public void testGetPerformance() {
    _testMap.clear();

    IntStream.range(0, _noOfPuts)
        .forEach(i -> _testMap.put(TestUtils.getKey(_mapName, i), _twoMbTestString));

    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    TestUtils.runMultipleTimesAndVerifyAvgRuntime(
        i -> _testMap.size(),
        () -> {
          IntStream.range(0, _noOfPuts).forEach(i -> _testMap.get(TestUtils.getKey(_mapName, i)));
        },
        _noOfRunsToAverage,
        _secondInNanos * 3 / 2);
  }

  /** Test that 50 updates per second of 2 MB string values completes in 1 second. */
  @Test
  public void testPutPerformance() {
    _testMap.clear();

    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    TestUtils.runMultipleTimesAndVerifyAvgRuntime(
        i -> _testMap.size(),
        () -> {
          IntStream.range(0, _noOfPuts)
              .forEach(i -> _testMap.put(TestUtils.getKey(_mapName, i), _twoMbTestString));
        },
        _noOfRunsToAverage,
        _secondInNanos);
  }

  /**
   * Test that listening to events for a given key can handle 50 updates per second of 2 MB string
   * values.
   */
  @Test
  public void testSubscriptionMapEventOnKeyPerformance() {
    _testMap.clear();

    String key = TestUtils.getKey(_mapName, 0);

    // Create subscriber and register
    // Add 4 for the number of puts that is added to the string
    TestChronicleKeyEventSubscriber keyEventSubscriber =
        new TestChronicleKeyEventSubscriber(_twoMbTestStringLength);

    clientAssetTree.registerSubscriber(
        _mapName + "/" + key + "?bootstrap=false", String.class, keyEventSubscriber);
    Jvm.pause(100);
    Asset child = serverAssetTree.getAsset(_mapName).getChild(key);
    Assert.assertNotNull(child);
    Subscription subscription = child.subscription(false);
    Assert.assertEquals(1, subscription.subscriberCount());

    long start = System.nanoTime();
    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    TestUtils.runMultipleTimesAndVerifyAvgRuntime(
        () -> {
          IntStream.range(0, _noOfPuts)
              .forEach(
                  i -> {
                    _testMap.put(key, _twoMbTestString);
                  });
        },
        _noOfRunsToAverage,
        3 * _secondInNanos);

    waitFor(() -> keyEventSubscriber.getNoOfEvents().get() >= _noOfPuts * _noOfRunsToAverage);
    long time = System.nanoTime() - start;
    System.out.printf("Took %.3f seconds to receive all events%n", time / 1e9);

    // Test that the correct number of events was triggered on event listener
    Assert.assertEquals(_noOfPuts * _noOfRunsToAverage, keyEventSubscriber.getNoOfEvents().get());

    clientAssetTree.unregisterSubscriber(_mapName + "/" + key, keyEventSubscriber);

    Jvm.pause(100);
    Assert.assertEquals(0, subscription.subscriberCount());
  }

  /**
   * Test that listening to events for a given map can handle 50 updates per second of 2 MB string
   * values and are triggering events which contain both the key and value (topic).
   */
  @Test
  public void testSubscriptionMapEventOnTopicPerformance() {
    _testMap.clear();

    String key = TestUtils.getKey(_mapName, 0);

    // Create subscriber and register
    TestChronicleTopicSubscriber topicSubscriber =
        new TestChronicleTopicSubscriber(key, _twoMbTestStringLength);

    clientAssetTree.registerTopicSubscriber(_mapName, String.class, String.class, topicSubscriber);

    Jvm.pause(100);
    KVSSubscription subscription =
        (KVSSubscription) serverAssetTree.getAsset(_mapName).subscription(false);
    Assert.assertEquals(1, subscription.topicSubscriberCount());

    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    TestUtils.runMultipleTimesAndVerifyAvgRuntime(
        i -> {
          System.out.println("test");
          int events = _noOfPuts * i;
          waitFor(() -> events == topicSubscriber.getNoOfEvents().get());
          Assert.assertEquals(events, topicSubscriber.getNoOfEvents().get());
        },
        () -> {
          IntStream.range(0, _noOfPuts)
              .forEach(
                  i -> {
                    _testMap.put(key, _twoMbTestString);
                  });
        },
        _noOfRunsToAverage,
        3 * _secondInNanos);

    // Test that the correct number of events was triggered on event listener
    int events = _noOfPuts * _noOfRunsToAverage;
    waitFor(() -> events == topicSubscriber.getNoOfEvents().get());
    Assert.assertEquals(events, topicSubscriber.getNoOfEvents().get());

    clientAssetTree.unregisterTopicSubscriber(_mapName, topicSubscriber);
    waitFor(() -> 0 == subscription.topicSubscriberCount());
    Assert.assertEquals(0, subscription.topicSubscriberCount());
  }

  /**
   * Tests the performance of an event listener on the map for Insert events of 2 MB strings. Expect
   * it to handle at least 50 2 MB updates per second.
   */
  @Test
  public void testSubscriptionMapEventListenerInsertPerformance() {
    _testMap.clear();

    YamlLogging.setAll(true);
    // Create subscriber and register
    TestChronicleMapEventListener mapEventListener =
        new TestChronicleMapEventListener(_mapName, _twoMbTestStringLength);

    Subscriber<MapEvent> mapEventSubscriber = e -> e.apply(mapEventListener);
    clientAssetTree.registerSubscriber(_mapName, MapEvent.class, mapEventSubscriber);

    Jvm.pause(100);
    KVSSubscription subscription =
        (KVSSubscription) serverAssetTree.getAsset(_mapName).subscription(false);
    Assert.assertEquals(1, subscription.entrySubscriberCount());

    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    TestUtils.runMultipleTimesAndVerifyAvgRuntime(
        i -> {
          if (i > 0) {
            waitFor(() -> mapEventListener.getNoOfInsertEvents().get() >= _noOfPuts);
            Assert.assertEquals(_noOfPuts, mapEventListener.getNoOfInsertEvents().get());
          }
          // Test that the correct number of events were triggered on event listener
          Assert.assertEquals(0, mapEventListener.getNoOfRemoveEvents().get());
          Assert.assertEquals(0, mapEventListener.getNoOfUpdateEvents().get());

          _testMap.clear();

          mapEventListener.resetCounters();
        },
        () -> {
          IntStream.range(0, _noOfPuts)
              .forEach(
                  i -> {
                    _testMap.put(TestUtils.getKey(_mapName, i), _twoMbTestString);
                  });
        },
        _noOfRunsToAverage,
        2 * _secondInNanos);

    clientAssetTree.unregisterSubscriber(_mapName, mapEventSubscriber);

    Jvm.pause(1000);
    Assert.assertEquals(0, subscription.entrySubscriberCount());
  }

  /**
   * Tests the performance of an event listener on the map for Update events of 2 MB strings. Expect
   * it to handle at least 50 2 MB updates per second.
   */
  @Test
  public void testSubscriptionMapEventListenerUpdatePerformance() {
    _testMap.clear();

    // Put values before testing as we want to ignore the insert events
    Function<Integer, Object> putFunction =
        a -> _testMap.put(TestUtils.getKey(_mapName, a), _twoMbTestString);

    IntStream.range(0, _noOfPuts)
        .forEach(
            i -> {
              putFunction.apply(i);
            });

    Jvm.pause(100);
    // Create subscriber and register
    TestChronicleMapEventListener mapEventListener =
        new TestChronicleMapEventListener(_mapName, _twoMbTestStringLength);

    Subscriber<MapEvent> mapEventSubscriber = e -> e.apply(mapEventListener);
    clientAssetTree.registerSubscriber(
        _mapName + "?bootstrap=false", MapEvent.class, mapEventSubscriber);

    KVSSubscription subscription =
        (KVSSubscription) serverAssetTree.getAsset(_mapName).subscription(false);

    waitFor(() -> subscription.entrySubscriberCount() == 1);
    Assert.assertEquals(1, subscription.entrySubscriberCount());

    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    TestUtils.runMultipleTimesAndVerifyAvgRuntime(
        i -> {
          if (i > 0) {
            waitFor(() -> mapEventListener.getNoOfUpdateEvents().get() >= _noOfPuts);

            // Test that the correct number of events were triggered on event listener
            Assert.assertEquals(_noOfPuts, mapEventListener.getNoOfUpdateEvents().get());
          }
          Assert.assertEquals(0, mapEventListener.getNoOfInsertEvents().get());
          Assert.assertEquals(0, mapEventListener.getNoOfRemoveEvents().get());

          mapEventListener.resetCounters();
        },
        () -> {
          IntStream.range(0, _noOfPuts)
              .forEach(
                  i -> {
                    putFunction.apply(i);
                  });
        },
        _noOfRunsToAverage,
        3 * _secondInNanos);
    clientAssetTree.unregisterSubscriber(_mapName, mapEventSubscriber);

    waitFor(() -> subscription.entrySubscriberCount() == 0);
    Assert.assertEquals(0, subscription.entrySubscriberCount());
  }

  private void waitFor(BooleanSupplier b) {
    for (int i = 1; i <= 40; i++) if (!b.getAsBoolean()) Jvm.pause(i * i);
  }

  /**
   * Tests the performance of an event listener on the map for Remove events of 2 MB strings. Expect
   * it to handle at least 50 2 MB updates per second.
   */
  @Test
  public void testSubscriptionMapEventListenerRemovePerformance() {
    _testMap.clear();
    // Put values before testing as we want to ignore the insert and update events

    // Create subscriber and register
    TestChronicleMapEventListener mapEventListener =
        new TestChronicleMapEventListener(_mapName, _twoMbTestStringLength);

    Subscriber<MapEvent> mapEventSubscriber = e -> e.apply(mapEventListener);
    clientAssetTree.registerSubscriber(_mapName, MapEvent.class, mapEventSubscriber);

    // Perform test a number of times to allow the JVM to warm up, but verify runtime against
    // average
    long runtimeInNanos = 0;

    for (int i = 0; i < _noOfRunsToAverage; i++) {
      // Put values before testing as we want to ignore the insert and update events
      IntStream.range(0, _noOfPuts)
          .forEach(
              c -> {
                _testMap.put(TestUtils.getKey(_mapName, c), _twoMbTestString);
              });
      waitFor(() -> mapEventListener.getNoOfInsertEvents().get() >= _noOfPuts);

      mapEventListener.resetCounters();

      long startTime = System.nanoTime();

      IntStream.range(0, _noOfPuts)
          .forEach(
              c -> {
                _testMap.remove(TestUtils.getKey(_mapName, c));
              });

      runtimeInNanos += System.nanoTime() - startTime;
      waitFor(() -> mapEventListener.getNoOfRemoveEvents().get() >= _noOfPuts);

      // Test that the correct number of events were triggered on event listener
      Assert.assertEquals(0, mapEventListener.getNoOfInsertEvents().get());
      Assert.assertEquals(_noOfPuts, mapEventListener.getNoOfRemoveEvents().get());
      Assert.assertEquals(0, mapEventListener.getNoOfUpdateEvents().get());
    }

    Assert.assertTrue((runtimeInNanos / (_noOfPuts * _noOfRunsToAverage)) <= 2 * _secondInNanos);
    clientAssetTree.unregisterSubscriber(_mapName, mapEventSubscriber);
  }

  /**
   * Checks that all updates triggered are for the key specified in the constructor and increments
   * the number of updates.
   */
  class TestChronicleKeyEventSubscriber implements Subscriber<String> {
    private int _stringLength;
    private AtomicInteger _noOfEvents = new AtomicInteger(0);

    public TestChronicleKeyEventSubscriber(int stringLength) {
      _stringLength = stringLength;
    }

    public AtomicInteger getNoOfEvents() {
      return _noOfEvents;
    }

    @Override
    public void onMessage(String newValue) {
      if (newValue == null) {
        System.out.println("No value");
      } else {
        Assert.assertEquals(_stringLength, newValue.length());
        _noOfEvents.incrementAndGet();
      }
    }
  }

  /**
   * Topic subscriber checking for each message that it is for the right key (in constructor) and
   * the expected size value. Increments event counter which can be checked at the end of the test.
   */
  class TestChronicleTopicSubscriber implements TopicSubscriber<String, String> {
    private String _keyName;
    private int _stringLength;
    private AtomicInteger _noOfEvents = new AtomicInteger(0);

    public TestChronicleTopicSubscriber(String keyName, int stringLength) {
      _keyName = keyName;
      _stringLength = stringLength;
    }

    /**
     * Test that the topic/key is the one specified in constructor and the message is the expected
     * size.
     *
     * @throws InvalidSubscriberException
     */
    @Override
    public void onMessage(String topic, String message) throws InvalidSubscriberException {
      Assert.assertEquals(_keyName, topic);
      Assert.assertEquals(_stringLength, message.length());

      _noOfEvents.incrementAndGet();
    }

    public AtomicInteger getNoOfEvents() {
      return _noOfEvents;
    }
  }

  /**
   * Map event listener for performance testing. Checks that the key is the one expected and the
   * size of the value is as expected. Increments event specific counters that can be used to check
   * agains the expected number of events.
   */
  class TestChronicleMapEventListener implements MapEventListener<String, String> {
    private AtomicInteger _noOfInsertEvents = new AtomicInteger(0);
    private AtomicInteger _noOfUpdateEvents = new AtomicInteger(0);
    private AtomicInteger _noOfRemoveEvents = new AtomicInteger(0);

    private String _mapName;
    private int _stringLength;

    public TestChronicleMapEventListener(String mapName, int stringLength) {
      _mapName = mapName;
      _stringLength = stringLength;
    }

    @Override
    public void update(String assetName, String key, String oldValue, String newValue) {
      testKeyAndValue(key, newValue, _noOfUpdateEvents);
    }

    @Override
    public void insert(String assetName, String key, String value) {
      testKeyAndValue(key, value, _noOfInsertEvents);
    }

    @Override
    public void remove(String assetName, String key, String value) {
      testKeyAndValue(key, value, _noOfRemoveEvents);
    }

    public AtomicInteger getNoOfInsertEvents() {
      return _noOfInsertEvents;
    }

    public AtomicInteger getNoOfUpdateEvents() {
      return _noOfUpdateEvents;
    }

    public AtomicInteger getNoOfRemoveEvents() {
      return _noOfRemoveEvents;
    }

    public void resetCounters() {
      _noOfInsertEvents = new AtomicInteger(0);
      _noOfUpdateEvents = new AtomicInteger(0);
      _noOfRemoveEvents = new AtomicInteger(0);
    }

    private void testKeyAndValue(String key, String value, AtomicInteger counterToIncrement) {
      int counter = counterToIncrement.getAndIncrement();
      Assert.assertEquals(TestUtils.getKey(_mapName, counter), key);
      Assert.assertEquals(_stringLength, value.length());
    }
  }
}
Beispiel #4
0
/**
 * Tests for the {@code net.hydromatic.optiq.impl.mongodb} package.
 *
 * <p>Before calling this test, you need to populate MongoDB with the "zips" data set (as described
 * in HOWTO.md) and "foodmart" data set, as follows:
 *
 * <blockquote>
 *
 * <code>
 * JAR=~/.m2/repository/pentaho/mondrian-data-foodmart-json/
 * 0.3/mondrian-data-foodmart-json-0.3.jar<br>
 * mkdir /tmp/foodmart<br>
 * cd /tmp/foodmart<br>
 * jar xvf $JAR<br>
 * for i in *.json; do<br>
 * &nbsp;&nbsp;mongoimport --db foodmart --collection ${i/.json/} --file $i<br>
 * done<br>
 * </code>
 *
 * </blockquote>
 */
public class MongoAdapterTest {
  public static final String MONGO_FOODMART_SCHEMA =
      "     {\n"
          + "       type: 'custom',\n"
          + "       name: '_foodmart',\n"
          + "       factory: 'net.hydromatic.optiq.impl.mongodb.MongoSchemaFactory',\n"
          + "       operand: {\n"
          + "         host: 'localhost',\n"
          + "         database: 'foodmart'\n"
          + "       }\n"
          + "     },\n"
          + "     {\n"
          + "       name: 'foodmart',\n"
          + "       tables: [\n"
          + "         {\n"
          + "           name: 'sales_fact_1997',\n"
          + "           type: 'view',\n"
          + "           sql: 'select cast(_MAP[\\'product_id\\'] AS double) AS \"product_id\" from \"_foodmart\".\"sales_fact_1997\"'\n"
          + "         },\n"
          + "         {\n"
          + "           name: 'sales_fact_1998',\n"
          + "           type: 'view',\n"
          + "           sql: 'select cast(_MAP[\\'product_id\\'] AS double) AS \"product_id\" from \"_foodmart\".\"sales_fact_1998\"'\n"
          + "         },\n"
          + "         {\n"
          + "           name: 'store',\n"
          + "           type: 'view',\n"
          + "           sql: 'select cast(_MAP[\\'store_id\\'] AS double) AS \"store_id\", cast(_MAP[\\'store_name\\'] AS varchar(20)) AS \"store_name\" from \"_foodmart\".\"store\"'\n"
          + "         },\n"
          + "         {\n"
          + "           name: 'warehouse',\n"
          + "           type: 'view',\n"
          + "           sql: 'select cast(_MAP[\\'warehouse_id\\'] AS double) AS \"warehouse_id\", cast(_MAP[\\'warehouse_state_province\\'] AS varchar(20)) AS \"warehouse_state_province\" from \"_foodmart\".\"warehouse\"'\n"
          + "         }\n"
          + "       ]\n"
          + "     }\n";

  public static final String MONGO_FOODMART_MODEL =
      "{\n"
          + "  version: '1.0',\n"
          + "  defaultSchema: 'foodmart',\n"
          + "   schemas: [\n"
          + MONGO_FOODMART_SCHEMA
          + "   ]\n"
          + "}";

  /** Connection factory based on the "mongo-zips" model. */
  public static final ImmutableMap<String, String> ZIPS =
      ImmutableMap.of(
          "model", MongoAdapterTest.class.getResource("/mongo-zips-model.json").getPath());

  /** Connection factory based on the "mongo-zips" model. */
  public static final ImmutableMap<String, String> FOODMART =
      ImmutableMap.of(
          "model", MongoAdapterTest.class.getResource("/mongo-foodmart-model.json").getPath());

  /**
   * Whether to run Mongo tests. Disabled by default, because we do not expect Mongo to be installed
   * and populated with the FoodMart data set. To enable, specify {@code -Doptiq.test.mongodb=true}
   * on the Java command line.
   */
  public static final boolean ENABLED = Boolean.getBoolean("optiq.test.mongodb");

  /** Whether to run this test. */
  protected boolean enabled() {
    return ENABLED;
  }

  /**
   * Returns a function that checks that a particular MongoDB pipeline is generated to implement a
   * query.
   */
  private static Function1<List, Void> mongoChecker(final String... strings) {
    return new Function1<List, Void>() {
      public Void apply(List actual) {
        if (!actual.contains(ImmutableList.copyOf(strings))) {
          Assert.fail("expected MongoDB query not found; actual: " + actual);
        }
        return null;
      }
    };
  }

  static Function1<ResultSet, Void> checkResultUnordered(final String... lines) {
    return new Function1<ResultSet, Void>() {
      public Void apply(ResultSet resultSet) {
        try {
          final List<String> expectedList = new ArrayList<String>();
          Collections.addAll(expectedList, lines);
          Collections.sort(expectedList);

          final List<String> actualList = new ArrayList<String>();
          OptiqAssert.toStringList(resultSet, actualList);
          for (int i = 0; i < actualList.size(); i++) {
            String s = actualList.get(i);
            actualList.set(i, s.replaceAll("\\.0;", ";").replaceAll("\\.0$", ""));
          }
          Collections.sort(actualList);

          assertThat(actualList, equalTo(expectedList));
          return null;
        } catch (SQLException e) {
          throw new RuntimeException(e);
        }
      }
    };
  }

  @Test
  public void testSort() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select * from zips order by state")
        .returnsCount(29467)
        .explainContains(
            "PLAN=MongoToEnumerableConverter\n"
                + "  MongoSortRel(sort0=[$4], dir0=[ASC])\n"
                + "    MongoProjectRel(CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], LONGITUDE=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT NOT NULL], LATITUDE=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT NOT NULL], POP=[CAST(ITEM($0, 'pop')):INTEGER], STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], ID=[CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
                + "      MongoTableScan(table=[[mongo_raw, zips]])");
  }

  @Test
  public void testSortLimit() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select state, id from zips\n"
                + "order by state, id offset 2 rows fetch next 3 rows only")
        .returns("STATE=AK; ID=99502\n" + "STATE=AK; ID=99503\n" + "STATE=AK; ID=99504\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state', ID: '$_id'}}",
                "{$sort: {STATE: 1, ID: 1}}",
                "{$skip: 2}",
                "{$limit: 3}"));
  }

  @Test
  public void testOffsetLimit() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, id from zips\n" + "offset 2 fetch next 3 rows only")
        .runs()
        .queryContains(
            mongoChecker("{$skip: 2}", "{$limit: 3}", "{$project: {STATE: '$state', ID: '$_id'}}"));
  }

  @Test
  public void testLimit() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, id from zips\n" + "fetch next 3 rows only")
        .runs()
        .queryContains(mongoChecker("{$limit: 3}", "{$project: {STATE: '$state', ID: '$_id'}}"));
  }

  @Test
  public void testFilterSort() {
    // LONGITUDE and LATITUDE are null because of OPTIQ-194.
    Util.discard(Bug.OPTIQ_194_FIXED);
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select * from zips\n"
                + "where city = 'SPRINGFIELD' and id between '20000' and '30000'\n"
                + "order by state")
        .returns(
            "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=2184; STATE=SC; ID=29146\n"
                + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=16811; STATE=VA; ID=22150\n"
                + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=32161; STATE=VA; ID=22153\n"
                + "CITY=SPRINGFIELD; LONGITUDE=null; LATITUDE=null; POP=1321; STATE=WV; ID=26763\n")
        .queryContains(
            mongoChecker(
                "{\n"
                    + "  $match: {\n"
                    + "    city: \"SPRINGFIELD\",\n"
                    + "    _id: {\n"
                    + "      $lte: \"30000\",\n"
                    + "      $gte: \"20000\"\n"
                    + "    }\n"
                    + "  }\n"
                    + "}",
                "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}",
                "{$sort: {STATE: 1}}"))
        .explainContains(
            "PLAN=MongoToEnumerableConverter\n"
                + "  MongoSortRel(sort0=[$4], dir0=[ASC])\n"
                + "    MongoProjectRel(CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], LONGITUDE=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT NOT NULL], LATITUDE=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT NOT NULL], POP=[CAST(ITEM($0, 'pop')):INTEGER], STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], ID=[CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
                + "      MongoFilterRel(condition=[AND(=(CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'SPRINGFIELD'), >=(CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", '20000'), <=(CAST(ITEM($0, '_id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", '30000'))])\n"
                + "        MongoTableScan(table=[[mongo_raw, zips]])");
  }

  @Test
  public void testFilterSortDesc() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select * from zips\n"
                + "where pop BETWEEN 20000 AND 20100\n"
                + "order by state desc, pop")
        .limit(4)
        .returns(
            "CITY=SHERIDAN; LONGITUDE=null; LATITUDE=null; POP=20025; STATE=WY; ID=82801\n"
                + "CITY=MOUNTLAKE TERRAC; LONGITUDE=null; LATITUDE=null; POP=20059; STATE=WA; ID=98043\n"
                + "CITY=FALMOUTH; LONGITUDE=null; LATITUDE=null; POP=20039; STATE=VA; ID=22405\n"
                + "CITY=FORT WORTH; LONGITUDE=null; LATITUDE=null; POP=20012; STATE=TX; ID=76104\n");
  }

  @Test
  public void testUnionPlan() {
    OptiqAssert.that()
        .enable(enabled())
        .withModel(MONGO_FOODMART_MODEL)
        .query(
            "select * from \"sales_fact_1997\"\n"
                + "union all\n"
                + "select * from \"sales_fact_1998\"")
        .explainContains(
            "PLAN=EnumerableUnionRel(all=[true])\n"
                + "  MongoToEnumerableConverter\n"
                + "    MongoProjectRel(product_id=[CAST(ITEM($0, 'product_id')):DOUBLE])\n"
                + "      MongoTableScan(table=[[_foodmart, sales_fact_1997]])\n"
                + "  MongoToEnumerableConverter\n"
                + "    MongoProjectRel(product_id=[CAST(ITEM($0, 'product_id')):DOUBLE])\n"
                + "      MongoTableScan(table=[[_foodmart, sales_fact_1998]])\n")
        .limit(2)
        .returns(checkResultUnordered("product_id=337", "product_id=1512"));
  }

  @Test
  public void testFilterUnionPlan() {
    OptiqAssert.that()
        .enable(enabled())
        .withModel(MONGO_FOODMART_MODEL)
        .query(
            "select * from (\n"
                + "  select * from \"sales_fact_1997\"\n"
                + "  union all\n"
                + "  select * from \"sales_fact_1998\")\n"
                + "where \"product_id\" = 1")
        .runs();
  }

  /**
   * Tests that we don't generate multiple constraints on the same column. MongoDB doesn't like it.
   * If there is an '=', it supersedes all other operators.
   */
  @Test
  public void testFilterRedundant() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select * from zips where state > 'CA' and state < 'AZ' and state = 'OK'")
        .runs()
        .queryContains(
            mongoChecker(
                "{\n" + "  $match: {\n" + "    state: \"OK\"\n" + "  }\n" + "}",
                "{$project: {CITY: '$city', LONGITUDE: '$loc[0]', LATITUDE: '$loc[1]', POP: '$pop', STATE: '$state', ID: '$_id'}}"));
  }

  @Test
  public void testSelectWhere() {
    OptiqAssert.that()
        .enable(enabled())
        .withModel(MONGO_FOODMART_MODEL)
        .query("select * from \"warehouse\" where \"warehouse_state_province\" = 'CA'")
        .explainContains(
            "PLAN=MongoToEnumerableConverter\n"
                + "  MongoProjectRel(warehouse_id=[CAST(ITEM($0, 'warehouse_id')):DOUBLE], warehouse_state_province=[CAST(ITEM($0, 'warehouse_state_province')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
                + "    MongoFilterRel(condition=[=(CAST(ITEM($0, 'warehouse_state_province')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n"
                + "      MongoTableScan(table=[[_foodmart, warehouse]])")
        .returns(
            checkResultUnordered(
                "warehouse_id=6; warehouse_state_province=CA",
                "warehouse_id=7; warehouse_state_province=CA",
                "warehouse_id=14; warehouse_state_province=CA",
                "warehouse_id=24; warehouse_state_province=CA"))
        .queryContains(
            // Per https://issues.apache.org/jira/browse/OPTIQ-164,
            // $match must occur before $project for good performance.
            mongoChecker(
                "{\n" + "  $match: {\n" + "    warehouse_state_province: \"CA\"\n" + "  }\n" + "}",
                "{$project: {warehouse_id: 1, warehouse_state_province: 1}}"));
  }

  @Test
  public void testInPlan() {
    OptiqAssert.that()
        .enable(enabled())
        .withModel(MONGO_FOODMART_MODEL)
        .query(
            "select \"store_id\", \"store_name\" from \"store\"\n"
                + "where \"store_name\" in ('Store 1', 'Store 10', 'Store 11', 'Store 15', 'Store 16', 'Store 24', 'Store 3', 'Store 7')")
        .returns(
            checkResultUnordered(
                "store_id=1; store_name=Store 1",
                "store_id=3; store_name=Store 3",
                "store_id=7; store_name=Store 7",
                "store_id=10; store_name=Store 10",
                "store_id=11; store_name=Store 11",
                "store_id=15; store_name=Store 15",
                "store_id=16; store_name=Store 16",
                "store_id=24; store_name=Store 24"))
        .queryContains(
            mongoChecker(
                "{\n"
                    + "  $match: {\n"
                    + "    $or: [\n"
                    + "      {\n"
                    + "        store_name: \"Store 1\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 10\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 11\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 15\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 16\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 24\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 3\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        store_name: \"Store 7\"\n"
                    + "      }\n"
                    + "    ]\n"
                    + "  }\n"
                    + "}",
                "{$project: {store_id: 1, store_name: 1}}"));
  }

  /** Simple query based on the "mongo-zips" model. */
  @Test
  public void testZips() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, city from zips")
        .returnsCount(29467);
  }

  @Test
  public void testCountGroupByEmpty() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select count(*) from zips")
        .returns("EXPR$0=29467\n")
        .explainContains(
            "PLAN=MongoToEnumerableConverter\n"
                + "  MongoAggregateRel(group=[{}], EXPR$0=[COUNT()])\n"
                + "    MongoProjectRel(DUMMY=[0])\n"
                + "      MongoTableScan(table=[[mongo_raw, zips]])")
        .queryContains(
            mongoChecker(
                "{$project: {DUMMY: {$ifNull: [null, 0]}}}",
                "{$group: {_id: {}, 'EXPR$0': {$sum: 1}}}"));
  }

  @Test
  public void testGroupByOneColumnNotProjected() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select count(*) from zips group by state")
        .limit(2)
        .returns("EXPR$0=659\n" + "EXPR$0=484\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state'}}",
                "{$group: {_id: '$STATE', 'EXPR$0': {$sum: 1}}}",
                "{$project: {STATE: '$_id', 'EXPR$0': '$EXPR$0'}}",
                "{$project: {'EXPR$0': 1}}"));
  }

  @Test
  public void testGroupByOneColumn() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, count(*) as c from zips group by state")
        .limit(2)
        .returns("STATE=WV; C=659\n" + "STATE=WA; C=484\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state'}}",
                "{$group: {_id: '$STATE', C: {$sum: 1}}}",
                "{$project: {STATE: '$_id', C: '$C'}}"));
  }

  @Test
  public void testGroupByOneColumnReversed() {
    // Note extra $project compared to testGroupByOneColumn.
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select count(*) as c, state from zips group by state")
        .limit(2)
        .returns("C=659; STATE=WV\n" + "C=484; STATE=WA\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state'}}",
                "{$group: {_id: '$STATE', C: {$sum: 1}}}",
                "{$project: {STATE: '$_id', C: '$C'}}",
                "{$project: {C: 1, STATE: 1}}"));
  }

  @Test
  public void testGroupByHaving() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, count(*) as c from zips\n" + "group by state having count(*) > 1500")
        .returns("STATE=NY; C=1596\n" + "STATE=TX; C=1676\n" + "STATE=CA; C=1523\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state'}}",
                "{$group: {_id: '$STATE', C: {$sum: 1}}}",
                "{$project: {STATE: '$_id', C: '$C'}}",
                "{\n"
                    + "  $match: {\n"
                    + "    C: {\n"
                    + "      $gt: 1500\n"
                    + "    }\n"
                    + "  }\n"
                    + "}"));
  }

  @Ignore("https://issues.apache.org/jira/browse/OPTIQ-270")
  @Test
  public void testGroupByHaving2() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select state, count(*) as c from zips\n" + "group by state having sum(pop) > 12000000")
        .returns(
            "STATE=NY; C=1596\n"
                + "STATE=TX; C=1676\n"
                + "STATE=FL; C=826\n"
                + "STATE=CA; C=1523\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state', POP: '$pop'}}",
                "{$group: {_id: '$STATE', C: {$sum: 1}, _2: {$sum: '$POP'}}}",
                "{$project: {STATE: '$_id', C: '$C', _2: '$_2'}}",
                "{\n"
                    + "  $match: {\n"
                    + "    _2: {\n"
                    + "      $gt: 12000000\n"
                    + "    }\n"
                    + "  }\n"
                    + "}",
                "{$project: {STATE: 1, C: 1}}"));
  }

  @Test
  public void testGroupByMinMaxSum() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select count(*) as c, state,\n"
                + " min(pop) as min_pop, max(pop) as max_pop, sum(pop) as sum_pop\n"
                + "from zips group by state")
        .limit(2)
        .returns(
            "C=659; STATE=WV; MIN_POP=0; MAX_POP=70185; SUM_POP=1793477\n"
                + "C=484; STATE=WA; MIN_POP=2; MAX_POP=50515; SUM_POP=4866692\n");
  }

  @Test
  public void testGroupComposite() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select count(*) as c, state, city from zips\n"
                + "group by state, city order by c desc limit 2")
        .returns("C=93; STATE=TX; CITY=HOUSTON\n" + "C=56; STATE=CA; CITY=LOS ANGELES\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state', CITY: '$city'}}",
                "{$group: {_id: {STATE: '$STATE', CITY: '$CITY'}, C: {$sum: 1}}}",
                "{$project: {_id: 0, STATE: '$_id.STATE', CITY: '$_id.CITY', C: '$C'}}",
                "{$project: {C: 1, STATE: 1, CITY: 1}}",
                "{$sort: {C: -1}}",
                "{$limit: 2}"));
  }

  @Test
  public void testDistinctCount() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select state, count(distinct city) as cdc from zips\n"
                + "where state in ('CA', 'TX') group by state")
        .returns("STATE=CA; CDC=1079\n" + "STATE=TX; CDC=1238\n")
        .queryContains(
            mongoChecker(
                "{\n"
                    + "  $match: {\n"
                    + "    $or: [\n"
                    + "      {\n"
                    + "        state: \"CA\"\n"
                    + "      },\n"
                    + "      {\n"
                    + "        state: \"TX\"\n"
                    + "      }\n"
                    + "    ]\n"
                    + "  }\n"
                    + "}",
                "{$project: {STATE: '$state', CITY: '$city'}}",
                "{$group: {_id: {STATE: '$STATE', CITY: '$CITY'}}}",
                "{$project: {_id: 0, STATE: '$_id.STATE', CITY: '$_id.CITY'}}",
                "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}",
                "{$project: {STATE: '$_id', CDC: '$CDC'}}"));
  }

  @Test
  public void testDistinctCountOrderBy() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query(
            "select state, count(distinct city) as cdc\n"
                + "from zips\n"
                + "group by state\n"
                + "order by cdc desc limit 5")
        .returns(
            "STATE=NY; CDC=1371\n"
                + "STATE=PA; CDC=1369\n"
                + "STATE=TX; CDC=1238\n"
                + "STATE=IL; CDC=1151\n"
                + "STATE=CA; CDC=1079\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state', CITY: '$city'}}",
                "{$group: {_id: {STATE: '$STATE', CITY: '$CITY'}}}",
                "{$project: {_id: 0, STATE: '$_id.STATE', CITY: '$_id.CITY'}}",
                "{$group: {_id: '$STATE', CDC: {$sum: {$cond: [ {$eq: ['CITY', null]}, 0, 1]}}}}",
                "{$project: {STATE: '$_id', CDC: '$CDC'}}",
                "{$sort: {CDC: -1}}",
                "{$limit: 5}"));
  }

  @Test
  public void testProject() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, city, 0 as zero from zips")
        .limit(2)
        .returns("STATE=AL; CITY=ACMAR; ZERO=0\n" + "STATE=AL; CITY=ADAMSVILLE; ZERO=0\n")
        .queryContains(
            mongoChecker(
                "{$project: {STATE: '$state', CITY: '$city', ZERO: {$ifNull: [null, 0]}}}"));
  }

  @Test
  public void testFilter() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, city from zips where state = 'CA'")
        .limit(2)
        .returns("STATE=CA; CITY=LOS ANGELES\n" + "STATE=CA; CITY=LOS ANGELES\n")
        .explainContains(
            "PLAN=MongoToEnumerableConverter\n"
                + "  MongoProjectRel(STATE=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], CITY=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
                + "    MongoFilterRel(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n"
                + "      MongoTableScan(table=[[mongo_raw, zips]])");
  }

  /**
   * MongoDB's predicates are handed (they can only accept literals on the right-hand size) so it's
   * worth testing that we handle them right both ways around.
   */
  @Test
  public void testFilterReversed() {
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, city from zips where 'WI' < state")
        .limit(2)
        .returns("STATE=WV; CITY=BLUEWELL\n" + "STATE=WV; CITY=ATHENS\n");
    OptiqAssert.that()
        .enable(enabled())
        .with(ZIPS)
        .query("select state, city from zips where state > 'WI'")
        .limit(2)
        .returns("STATE=WV; CITY=BLUEWELL\n" + "STATE=WV; CITY=ATHENS\n");
  }

  @Ignore
  @Test
  public void testFoodmartQueries() {
    final List<Pair<String, String>> queries = JdbcTest.getFoodmartQueries();
    for (Ord<Pair<String, String>> query : Ord.zip(queries)) {
      //      if (query.i != 29) continue;
      if (query.e.left.contains("agg_")) {
        continue;
      }
      final OptiqAssert.AssertQuery query1 =
          OptiqAssert.that().enable(enabled()).with(FOODMART).query(query.e.left);
      if (query.e.right != null) {
        query1.returns(query.e.right);
      } else {
        query1.runs();
      }
    }
  }

  /**
   * Test case for <a href="https://issues.apache.org/jira/browse/OPTIQ-286">OPTIQ-286</a>, "Error
   * casting MongoDB date".
   */
  @Test
  public void testDate() {
    // Assumes that you have created the following collection before running
    // this test:
    //
    // $ mongo
    // > use test
    // switched to db test
    // > db.createCollection("datatypes")
    // { "ok" : 1 }
    // > db.datatypes.insert( {
    //     "_id" : ObjectId("53655599e4b0c980df0a8c27"),
    //     "_class" : "com.ericblue.Test",
    //     "date" : ISODate("2012-09-05T07:00:00Z"),
    //     "value" : 1231,
    //     "ownerId" : "531e7789e4b0853ddb861313"
    //   } )
    OptiqAssert.that()
        .enable(enabled())
        .withModel(
            "{\n"
                + "  version: '1.0',\n"
                + "  defaultSchema: 'test',\n"
                + "   schemas: [\n"
                + "     {\n"
                + "       type: 'custom',\n"
                + "       name: 'test',\n"
                + "       factory: 'net.hydromatic.optiq.impl.mongodb.MongoSchemaFactory',\n"
                + "       operand: {\n"
                + "         host: 'localhost',\n"
                + "         database: 'test'\n"
                + "       }\n"
                + "     }\n"
                + "   ]\n"
                + "}")
        .query("select cast(_MAP['date'] as DATE) from \"datatypes\"")
        .returnsUnordered("EXPR$0=2012-09-05");
  }
}