@Test
  public void testProcessEndtimeUpdate() throws Exception {
    scheduleProcess();
    waitForBundleStart(Job.Status.RUNNING);

    ClientResponse response =
        this.service
            .path("api/entities/definition/process/" + processName)
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .get(ClientResponse.class);
    Process process =
        (Process)
            EntityType.PROCESS
                .getUnmarshaller()
                .unmarshal(new StringReader(response.getEntity(String.class)));

    Validity processValidity = process.getClusters().getClusters().get(0).getValidity();
    processValidity.setEnd(new Date(new Date().getTime() + 60 * 60 * 1000));
    File tmpFile = getTempFile();
    EntityType.PROCESS.getMarshaller().marshal(process, tmpFile);
    response =
        this.service
            .path("api/entities/update/process/" + processName)
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .post(ClientResponse.class, getServletInputStream(tmpFile.getAbsolutePath()));
    assertSuccessful(response);

    // Assert that update does not create new bundle
    List<BundleJob> bundles = getBundles();
    Assert.assertEquals(bundles.size(), 1);
  }
  @Test
  public void testShouldUpdate() throws Exception {
    Feed oldFeed = parser.parseAndValidate(this.getClass().getResourceAsStream(FEED_XML));

    Feed newFeed = (Feed) oldFeed.clone();
    Process process =
        processParser.parseAndValidate(this.getClass().getResourceAsStream(PROCESS_XML));

    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    newFeed.getLateArrival().setCutOff(Frequency.fromString("hours(1)"));
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    newFeed.getLateArrival().setCutOff(oldFeed.getLateArrival().getCutOff());
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    FeedHelper.getLocation(newFeed, LocationType.DATA).setPath("/test");
    Assert.assertTrue(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    FeedHelper.getLocation(newFeed, LocationType.DATA)
        .setPath(FeedHelper.getLocation(oldFeed, LocationType.DATA).getPath());
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    newFeed.setFrequency(Frequency.fromString("months(1)"));
    Assert.assertTrue(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    newFeed.setFrequency(oldFeed.getFrequency());
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    Partition partition = new Partition();
    partition.setName("1");
    newFeed.getPartitions().getPartitions().add(partition);
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    Property property = new Property();
    property.setName("1");
    property.setValue("1");
    newFeed.setProperties(new Properties());
    newFeed.getProperties().getProperties().add(property);
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    newFeed.getProperties().getProperties().remove(0);
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    FeedHelper.getCluster(newFeed, process.getClusters().getClusters().get(0).getName())
        .getValidity()
        .setStart(SchemaHelper.parseDateUTC("2012-11-01T00:00Z"));
    Assert.assertTrue(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));

    FeedHelper.getCluster(newFeed, process.getClusters().getClusters().get(0).getName())
        .getValidity()
        .setStart(
            FeedHelper.getCluster(oldFeed, process.getClusters().getClusters().get(0).getName())
                .getValidity()
                .getStart());
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, process));
  }
  /**
   * Tests should be enabled only in local environments as they need running instance of webserver
   */
  @Test
  public void testUpdateCheckUser() throws Exception {
    Map<String, String> overlay = getUniqueOverlay();
    String tmpFileName = overlayParametersOverTemplate(PROCESS_TEMPLATE, overlay);
    Process process =
        (Process) EntityType.PROCESS.getUnmarshaller().unmarshal(new File(tmpFileName));
    Validity processValidity = process.getClusters().getClusters().get(0).getValidity();
    processValidity.setEnd(new Date(new Date().getTime() + 2 * 24 * 60 * 60 * 1000));
    File tmpFile = getTempFile();
    EntityType.PROCESS.getMarshaller().marshal(process, tmpFile);
    scheduleProcess(tmpFile.getAbsolutePath(), overlay);
    waitForBundleStart(Status.RUNNING);

    List<BundleJob> bundles = getBundles();
    Assert.assertEquals(bundles.size(), 1);
    Assert.assertEquals(bundles.get(0).getUser(), REMOTE_USER);

    ClientResponse response =
        this.service
            .path("api/entities/definition/feed/" + outputFeedName)
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .get(ClientResponse.class);
    Feed feed =
        (Feed)
            EntityType.FEED
                .getUnmarshaller()
                .unmarshal(new StringReader(response.getEntity(String.class)));

    // change output feed path and update feed as another user
    feed.getLocations()
        .getLocations()
        .get(0)
        .setPath("/ivory/test/output2/${YEAR}/${MONTH}/${DAY}");
    tmpFile = getTempFile();
    EntityType.FEED.getMarshaller().marshal(feed, tmpFile);
    response =
        this.service
            .path("api/entities/update/feed/" + outputFeedName)
            .header("Remote-User", "testuser")
            .accept(MediaType.TEXT_XML)
            .post(ClientResponse.class, getServletInputStream(tmpFile.getAbsolutePath()));
    assertSuccessful(response);

    bundles = getBundles();
    Assert.assertEquals(bundles.size(), 2);
    Assert.assertEquals(bundles.get(0).getUser(), REMOTE_USER);
    Assert.assertEquals(bundles.get(1).getUser(), REMOTE_USER);
  }
  @Test
  public void testProcessInputUpdate() throws Exception {
    scheduleProcess();
    waitForBundleStart(Job.Status.RUNNING);

    ClientResponse response =
        this.service
            .path("api/entities/definition/process/" + processName)
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .get(ClientResponse.class);
    Process process =
        (Process)
            EntityType.PROCESS
                .getUnmarshaller()
                .unmarshal(new StringReader(response.getEntity(String.class)));

    String feed3 = "f3" + System.currentTimeMillis();
    Map<String, String> overlay = new HashMap<String, String>();
    overlay.put("inputFeedName", feed3);
    overlay.put("cluster", clusterName);
    response = submitToIvory(FEED_TEMPLATE1, overlay, EntityType.FEED);
    assertSuccessful(response);

    Input input = new Input();
    input.setFeed(feed3);
    input.setName("inputData2");
    input.setStart("today(20,0)");
    input.setEnd("today(20,20)");
    process.getInputs().getInputs().add(input);

    Validity processValidity = process.getClusters().getClusters().get(0).getValidity();
    processValidity.setEnd(new Date(new Date().getTime() + 2 * 24 * 60 * 60 * 1000));
    File tmpFile = getTempFile();
    EntityType.PROCESS.getMarshaller().marshal(process, tmpFile);
    response =
        this.service
            .path("api/entities/update/process/" + processName)
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .post(ClientResponse.class, getServletInputStream(tmpFile.getAbsolutePath()));
    assertSuccessful(response);

    // Assert that update creates new bundle
    List<BundleJob> bundles = getBundles();
    Assert.assertEquals(bundles.size(), 2);
  }
  @Test
  public void testShouldUpdate2() throws Exception {
    Feed oldFeed = parser.parseAndValidate(this.getClass().getResourceAsStream(FEED_XML));
    String cluster = "testCluster";
    Feed newFeed = (Feed) oldFeed.clone();
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, cluster));

    newFeed.setGroups("newgroups");
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, cluster));
    newFeed.getLateArrival().setCutOff(Frequency.fromString("hours(8)"));
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldFeed, newFeed, cluster));
    newFeed.setFrequency(Frequency.fromString("days(1)"));
    Assert.assertTrue(UpdateHelper.shouldUpdate(oldFeed, newFeed, cluster));

    Process oldProcess =
        processParser.parseAndValidate(this.getClass().getResourceAsStream(PROCESS_XML));
    Process newProcess = (Process) oldProcess.clone();

    newProcess.getRetry().setPolicy(PolicyType.FINAL);
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldProcess, newProcess, cluster));
    newProcess.getLateProcess().getLateInputs().remove(1);
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldProcess, newProcess, cluster));
    newProcess.getLateProcess().setPolicy(PolicyType.PERIODIC);
    Assert.assertFalse(UpdateHelper.shouldUpdate(oldProcess, newProcess, cluster));
    newProcess.setFrequency(Frequency.fromString("days(1)"));
    Assert.assertTrue(UpdateHelper.shouldUpdate(oldProcess, newProcess, cluster));
  }
  @Test
  public void testProcessDeleteAndSchedule() throws Exception {
    // Submit process with invalid property so that coord submit fails and bundle goes to failed
    // state
    Map<String, String> overlay = getUniqueOverlay();
    String tmpFileName = overlayParametersOverTemplate(PROCESS_TEMPLATE, overlay);
    Process process =
        (Process) EntityType.PROCESS.getUnmarshaller().unmarshal(new File(tmpFileName));
    Property prop = new Property();
    prop.setName("newProp");
    prop.setValue("${formatTim()}");
    process.getProperties().getProperties().add(prop);
    File tmpFile = getTempFile();
    EntityType.PROCESS.getMarshaller().marshal(process, tmpFile);
    scheduleProcess(tmpFile.getAbsolutePath(), overlay);
    waitForBundleStart(Status.FAILED);

    // Delete and re-submit the process with correct workflow
    ClientResponse clientRepsonse =
        this.service
            .path("api/entities/delete/process/" + processName)
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .delete(ClientResponse.class);
    assertSuccessful(clientRepsonse);
    process.getWorkflow().setPath("/ivory/test/workflow");
    tmpFile = getTempFile();
    EntityType.PROCESS.getMarshaller().marshal(process, tmpFile);
    clientRepsonse =
        this.service
            .path("api/entities/submitAndSchedule/process")
            .header("Remote-User", REMOTE_USER)
            .accept(MediaType.TEXT_XML)
            .type(MediaType.TEXT_XML)
            .post(ClientResponse.class, getServletInputStream(tmpFile.getAbsolutePath()));
    assertSuccessful(clientRepsonse);

    // Assert that new schedule creates new bundle
    List<BundleJob> bundles = getBundles();
    Assert.assertEquals(bundles.size(), 2);
  }
  @Test(enabled = false)
  public void testOptionalInput() throws Exception {
    Map<String, String> overlay = getUniqueOverlay();
    String tmpFileName = overlayParametersOverTemplate(PROCESS_TEMPLATE, overlay);
    Process process =
        (Process) EntityType.PROCESS.getUnmarshaller().unmarshal(new File(tmpFileName));

    Input in1 = process.getInputs().getInputs().get(0);
    Input in2 = new Input();
    in2.setFeed(in1.getFeed());
    in2.setName("input2");
    in2.setOptional(true);
    in2.setPartition(in1.getPartition());
    in2.setStart("now(-1,0)");
    in2.setEnd("now(0,0)");
    process.getInputs().getInputs().add(in2);

    File tmpFile = getTempFile();
    EntityType.PROCESS.getMarshaller().marshal(process, tmpFile);
    scheduleProcess(tmpFile.getAbsolutePath(), overlay);
    waitForWorkflowStart(processName);
  }