@Test
public void testFindExecutionsQuerySerialization() throws IOException {

    Assert.assertEquals(
            DXJSON.parseJson("{\"launchedBy\":\"user-user1\"}"),
            mapper.valueToTree(DXSearch.findExecutions().launchedBy("user-user1")
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"project\":\"project-000000000000000000000000\"}"),
            mapper.valueToTree(DXSearch.findExecutions()
                    .inProject(DXProject.getInstance("project-000000000000000000000000"))
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"includeSubjobs\": false}"),
            mapper.valueToTree(DXSearch.findExecutions().includeSubjobs(false)
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"name\": \"dnanexus\"}"),
            mapper.valueToTree(DXSearch.findExecutions().nameMatchesExactly("dnanexus")
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"name\": {\"regexp\": \"(DNA|dna)nexus\"}}"),
            mapper.valueToTree(DXSearch.findExecutions().nameMatchesRegexp("(DNA|dna)nexus")
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"name\": {\"regexp\": \"[dr]nanexus\"}}"),
            mapper.valueToTree(DXSearch.findExecutions()
                    .nameMatchesRegexp("[dr]nanexus", false).buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"name\": {\"regexp\": \"[dr]nanexus\", \"flags\": \"i\"}}"),
            mapper.valueToTree(DXSearch.findExecutions().nameMatchesRegexp("[dr]nanexus", true)
                    .buildRequestHash()));
    Assert.assertEquals(DXJSON.parseJson("{\"class\": \"job\"}"),
            mapper.valueToTree(DXSearch.findExecutions().withClassJob().buildRequestHash()));
    Assert.assertEquals(DXJSON.parseJson("{\"class\": \"analysis\"}"), mapper
            .valueToTree(DXSearch.findExecutions().withClassAnalysis().buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"executable\": \"applet-000011112222333344445555\"}"),
            mapper.valueToTree(DXSearch.findExecutions()
                    .withExecutable(DXApplet.getInstance("applet-000011112222333344445555"))
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"originJob\": \"job-000011112222333344445555\"}"),
            mapper.valueToTree(DXSearch.findExecutions()
                    .withOriginJob(DXJob.getInstance("job-000011112222333344445555"))
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"parentAnalysis\": \"analysis-000011112222333344445555\"}"),
            mapper.valueToTree(DXSearch
                    .findExecutions()
                    .withParentAnalysis(
                            DXAnalysis.getInstance("analysis-000011112222333344445555"))
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"parentJob\": \"job-000011112222333344445555\"}"),
            mapper.valueToTree(DXSearch.findExecutions()
                    .withParentJob(DXJob.getInstance("job-000011112222333344445555"))
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"properties\": {\"$and\": [{\"a\": \"b\"}, {\"c\": true}]}}"),
            mapper.valueToTree(DXSearch.findExecutions().withProperty("a", "b")
                    .withProperty("c").buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"rootExecution\": \"analysis-000011112222333344445555\"}"),
            mapper.valueToTree(DXSearch
                    .findExecutions()
                    .withRootExecution(
                            DXAnalysis.getInstance("analysis-000011112222333344445555"))
                    .buildRequestHash()));
    Assert.assertEquals(DXJSON.parseJson("{\"tags\": \"a\"}"),
            mapper.valueToTree(DXSearch.findExecutions().withTag("a").buildRequestHash()));
    Assert.assertEquals(DXJSON
            .parseJson("{\"tags\": {\"$or\": [{\"$and\": [\"a\", \"b\"]}, \"c\"]}}"), mapper
            .valueToTree(DXSearch
                    .findExecutions()
                    .withTags(
                            DXSearch.TagsQuery.anyOf(DXSearch.TagsQuery.allOf("a", "b"),
                                    DXSearch.TagsQuery.of("c"))).buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"state\": \"done\"}"),
            mapper.valueToTree(DXSearch.findExecutions().withState(JobState.DONE)
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"state\": [\"in_progress\", \"done\"]}"),
            mapper.valueToTree(DXSearch.findExecutions()
                    .withState(AnalysisState.IN_PROGRESS, AnalysisState.DONE)
                    .buildRequestHash()));
    Assert.assertEquals(DXJSON.parseJson("{\"properties\": {\"foo\": true}}"), mapper
            .valueToTree(DXSearch.findExecutions().withProperty("foo").buildRequestHash()));
    Assert.assertEquals(DXJSON
            .parseJson("{\"properties\": {\"$and\": [{\"foo\": true}, {\"bar\": \"a\"}]}}"),
            mapper.valueToTree(DXSearch.findExecutions().withProperty("foo")
                    .withProperty("bar", "a").buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"properties\": {\"$and\": [{\"foo\": true}, {\"bar\": \"a\"}, {\"baz\": \"b\"}]}}"),
            mapper.valueToTree(DXSearch.findExecutions().withProperty("foo")
                    .withProperty("bar", "a")
                    .withProperties(PropertiesQuery.withKeyAndValue("baz", "b"))
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"id\": [\"job-111100000000000000000000\"]}"),
            mapper.valueToTree(DXSearch
                    .findExecutions()
                    .withIdsIn(
                            ImmutableList.of(DXJob.getInstance("job-111100000000000000000000")))
                    .buildRequestHash()));
    // Conversion of dates to milliseconds since epoch
    GregorianCalendar january15 = new GregorianCalendar(2013, 0, 15);
    january15.setTimeZone(TimeZone.getTimeZone("UTC"));
    GregorianCalendar january16 = new GregorianCalendar(2013, 0, 16);
    january16.setTimeZone(TimeZone.getTimeZone("UTC"));
    Assert.assertEquals(
            DXJSON.parseJson("{\"created\": {\"before\": 1358208000000}}"),
            mapper.valueToTree(DXSearch.findExecutions().createdBefore(january15.getTime())
                    .buildRequestHash()));
    Assert.assertEquals(
            DXJSON.parseJson("{\"created\": {\"after\": 1358208000000}}"),
            mapper.valueToTree(DXSearch.findExecutions().createdAfter(january15.getTime())
                    .buildRequestHash()));
    Assert.assertEquals(DXJSON
            .parseJson("{\"created\": {\"after\": 1358208000000, \"before\": 1358294400000}}"),
            mapper.valueToTree(DXSearch.findExecutions().createdAfter(january15.getTime())
                    .createdBefore(january16.getTime()).buildRequestHash()));
    // Setting multiple fields
    Assert.assertEquals(
            DXJSON.parseJson("{\"launchedBy\":\"user-user1\", \"project\":\"project-000000000000000000000000\"}"),
            mapper.valueToTree(DXSearch.findExecutions().launchedBy("user-user1")
                    .inProject(DXProject.getInstance("project-000000000000000000000000"))
                    .buildRequestHash()));
    // Setting the same field more than once is disallowed
    try {
        DXSearch.findExecutions().launchedBy("user-user1").launchedBy("user-user2");
        Assert.fail("Expected double setting of launchedBy to fail");
    } catch (IllegalStateException e) {
        // Expected
    }
    try {
        DXSearch.findExecutions().inProject(DXProject.getInstance("project-0"))
                .inProject(DXProject.getInstance("project-1"));
        Assert.fail("Expected double setting of inProject to fail");
    } catch (IllegalStateException e) {
        // Expected
    }
    try {
        DXSearch.findExecutions().includeSubjobs(true).includeSubjobs(false);
        Assert.fail("Expected double setting of includeSubjobs to fail");
    } catch (IllegalStateException e) {
        // Expected
    }
    try {
        DXSearch.findExecutions().nameMatchesExactly("foo").nameMatchesGlob("g*");
        Assert.fail("Expected double setting of name queries to fail");
    } catch (IllegalStateException e) {
        // Expected
    }
    try {
        DXSearch.findExecutions().withClassAnalysis().withClassJob();
        Assert.fail("Expected double setting of class constraints to fail");
    } catch (IllegalStateException e) {
        // Expected
    }
    try {
        DXSearch.findExecutions().withIdsIn(ImmutableList.<DXExecution>of())
                .withIdsIn(ImmutableList.<DXExecution>of());
        Assert.fail("Expected double setting of withIdsIn to fail");
    } catch (IllegalStateException e) {
        // Expected
    }
    // TODO: includeDescribeOutput
}