@Test
public void testFindDataObjects() {

    DXRecord moo = DXRecord.newRecord().setProject(testProject).setName("Moo")
            .putProperty("sampleId", "1").putProperty("process", "a")
            .addTypes(ImmutableList.of("genome", "report")).build().close();
    sleep(1500); // sleep to break "created" timestamp ties
    DXRecord foo = DXRecord.newRecord().setProject(testProject).setName("foo")
            .putProperty("sampleId", "2").addTags(ImmutableList.of("mytag"))
            .addTypes(ImmutableList.of("genome")).build().close();
    sleep(1500);
    DXRecord food = DXRecord.newRecord().setProject(testProject).setName("food")
            .putProperty("process", "a").setFolder("/subfolder", true)
            .addTypes(ImmutableList.of("report")).build().close();
    sleep(1500);
    DXRecord open = DXRecord.newRecord().setProject(testProject).setName("open")
            .addTypes(ImmutableList.of("type")).build();
    DXRecord invisible =
            DXRecord.newRecord().setProject(testProject).setName("invisible")
                    .setVisibility(false).build().close();
    // nameMatches*
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().nameMatchesExactly("foo").inProject(testProject)
                    .execute().asList(), foo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().nameMatchesGlob("foo*").inProject(testProject).execute()
                    .asList(), foo, food);
    assertEqualsAnyOrder(DXSearch.findDataObjects().nameMatchesRegexp("[a-m]oo[^x]?")
            .inProject(testProject).execute().asList(), foo, food);
    assertEqualsAnyOrder(DXSearch.findDataObjects().nameMatchesRegexp("[a-m]oo[^x]?", true)
            .inProject(testProject).execute().asList(), moo, foo, food);
    // {created,modified}{Before,After}
    // We rely on the fact that
    // moo.created <= foo.created <= food.created <= open.created
    // with equality possible since the creation timestamp is encoded at
    // 1-sec resolution
    List<DXDataObject> createdBeforeResults =
            DXSearch.findDataObjects().inProject(testProject)
                    .createdBefore(moo.describe().getCreationDate()).execute().asList();
    Assert.assertTrue(1 <= createdBeforeResults.size() && createdBeforeResults.size() <= 4);
    Assert.assertTrue(createdBeforeResults.contains(moo));
    List<DXDataObject> createdAfterResults =
            DXSearch.findDataObjects().inProject(testProject)
                    .createdAfter(food.describe().getCreationDate()).execute().asList();
    Assert.assertTrue(2 <= createdAfterResults.size() && createdAfterResults.size() <= 4);
    Assert.assertTrue(createdAfterResults.contains(food));
    Assert.assertTrue(createdAfterResults.contains(open));
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .modifiedBefore(foo.describe().getModificationDate()).execute().asList(),
            moo, foo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .modifiedAfter(foo.describe().getModificationDate()).execute().asList(),
            foo, food, open);
    // inFolder and friends
    assertEqualsAnyOrder(DXSearch.findDataObjects().inFolder(testProject, "/").execute()
            .asList(), moo, foo, open);
    assertEqualsAnyOrder(DXSearch.findDataObjects().inFolderOrSubfolders(testProject, "/")
            .execute().asList(), moo, foo, food, open);
    // sortBy
    assertEqualsOrdered(DXSearch.findDataObjects().inFolder(testProject, "/")
            .withSortBy("created", DXSearch.Ordering.ASCENDING)
            .execute().asList(), moo, foo, open);
    assertEqualsAnyOrder(DXSearch.findDataObjects().inFolderOrSubfolders(testProject, "/")
            .withSortBy("created", DXSearch.Ordering.DESCENDING)
            .execute().asList(), open, foo, food, moo);
    // withProperty
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject).withProperty("sampleId")
                    .execute().asList(), moo, foo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject).withProperty("sampleId", "2")
                    .execute().asList(), foo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects()
                    .inProject(testProject)
                    .withProperties(
                            PropertiesQuery.allOf(PropertiesQuery.withKey("sampleId"),
                                    PropertiesQuery.withKeyAndValue("process", "a"))).execute()
                    .asList(), moo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects()
                    .inProject(testProject)
                    .withProperties(
                            PropertiesQuery.anyOf(PropertiesQuery.withKey("sampleId"),
                                    PropertiesQuery.withKeyAndValue("process", "a"))).execute()
                    .asList(), moo, foo, food);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withProperty("sampleId", false)
                    .execute().asList(), open, food);
    Map<String, String> notEqualMap = new HashMap<String, String>() {{ put("$ne", "1"); }};
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withProperty("sampleId", notEqualMap)
                    .execute().asList(), foo);
    Map<String, String> notEqual1 = new HashMap<String, String>() {{ put("$ne", "1"); }};
    Map<String, String> notEqual2 = new HashMap<String, String>() {{ put("$ne", "2"); }};
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withProperties(
                            PropertiesQuery.allOf(PropertiesQuery.withKeyAndMapValue("sampleId", notEqual1),
                                                  PropertiesQuery.withKeyAndMapValue("sampleId", notEqual2))
                    )
                    .execute().asList());
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withProperties(
                            PropertiesQuery.anyOf(PropertiesQuery.withKeyAndBoolean("sampleId", true),
                                                  PropertiesQuery.withKeyAndBoolean("process", false))
                    )
                    .execute().asList(), moo, foo, open);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withProperties(
                            PropertiesQuery.allOf(PropertiesQuery.withKeyAndBoolean("sampleId", true),
                                                  PropertiesQuery.withKeyAndBoolean("sampleId", false))
                    )
                    .execute().asList());
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withProperty("xyzxyzxyz", false)
                    .execute().asList(), moo, foo, food, open);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inFolderOrSubfolders(testProject, "/subfolder")
                    .withProperty("process", true)
                    .execute().asList(), food);
    // withState
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject).withState(DataObjectState.CLOSED)
                    .execute().asList(), moo, foo, food);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject).withState(DataObjectState.OPEN)
                    .execute().asList(), open);
    // withTags
    assertEqualsAnyOrder(DXSearch.findDataObjects().inProject(testProject).withTag("mytag")
            .execute().asList(), foo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withTags(DXSearch.TagsQuery.anyOf("mytag", "zyzzx")).execute().asList(),
            foo);
    // withTypes
    assertEqualsAnyOrder(DXSearch.findDataObjects().inProject(testProject).withType("genome")
            .execute().asList(), moo, foo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withTypes(TypeQuery.allOf("genome", "report")).execute().asList(), moo);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withTypes(TypeQuery.anyOf("genome", "report")).execute().asList(), moo,
            foo, food);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects()
                    .inProject(testProject)
                    .withTypes(
                            TypeQuery.anyOf(TypeQuery.allOf("genome", "report"),
                                    TypeQuery.of("type"))).execute().asList(), moo, open);
    // withVisibility
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withVisibility(DXSearch.VisibilityQuery.HIDDEN).execute().asList(),
            invisible);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withVisibility(DXSearch.VisibilityQuery.VISIBLE).execute().asList(), moo,
            foo, food, open);
    assertEqualsAnyOrder(
            DXSearch.findDataObjects().inProject(testProject)
                    .withVisibility(DXSearch.VisibilityQuery.EITHER).execute().asList(), moo,
            foo, food, open, invisible);
    // withIdsIn
    assertEqualsAnyOrder(DXSearch.findDataObjects().withIdsIn(ImmutableList.of(moo, foo))
            .execute().asList(), moo, foo);
    // Hidden objects don't get returned unless specifically requested
    assertEqualsAnyOrder(DXSearch.findDataObjects().withIdsIn(ImmutableList.of(moo, invisible))
            .execute().asList(), moo);
    assertEqualsAnyOrder(DXSearch.findDataObjects().withIdsIn(ImmutableList.of(moo, invisible))
            .withVisibility(VisibilityQuery.EITHER).execute().asList(), moo, invisible);
    // TODO: withLinkTo, withMinimumAccessLevel
}