/**
   * Test updating a single task variable using a binary stream. PUT
   * runtime/tasks/{taskId}/variables/{variableName}
   */
  public void testUpdateBinaryTaskVariable() throws Exception {
    try {
      Task task = taskService.newTask();
      taskService.saveTask(task);
      taskService.setVariable(task.getId(), "binaryVariable", "Original value".getBytes());

      InputStream binaryContent = new ByteArrayInputStream("This is binary content".getBytes());

      // Add name, type and scope
      Map<String, String> additionalFields = new HashMap<String, String>();
      additionalFields.put("name", "binaryVariable");
      additionalFields.put("type", "binary");
      additionalFields.put("scope", "local");

      // Upload a valid BPMN-file using multipart-data
      Representation uploadRepresentation =
          new HttpMultipartRepresentation("value", binaryContent, additionalFields);

      ClientResource client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE, task.getId(), "binaryVariable"));
      Representation response = client.put(uploadRepresentation);
      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

      JsonNode responseNode = objectMapper.readTree(response.getStream());
      assertNotNull(responseNode);
      assertEquals("binaryVariable", responseNode.get("name").asText());
      assertTrue(responseNode.get("value").isNull());
      assertEquals("local", responseNode.get("scope").asText());
      assertEquals("binary", responseNode.get("type").asText());
      assertNotNull(responseNode.get("valueUrl").isNull());
      assertTrue(
          responseNode
              .get("valueUrl")
              .asText()
              .endsWith(
                  RestUrls.createRelativeResourceUrl(
                      RestUrls.URL_TASK_VARIABLE_DATA, task.getId(), "binaryVariable")));

      // Check actual value of variable in engine
      Object variableValue = taskService.getVariableLocal(task.getId(), "binaryVariable");
      assertNotNull(variableValue);
      assertTrue(variableValue instanceof byte[]);
      assertEquals("This is binary content", new String((byte[]) variableValue));
    } finally {
      // Clean adhoc-tasks even if test fails
      List<Task> tasks = taskService.createTaskQuery().list();
      for (Task task : tasks) {
        taskService.deleteTask(task.getId(), true);
      }
    }
  }
  /** Test getting a task variable. GET runtime/tasks/{taskId}/variables/{variableName}/data */
  public void testGetTaskVariableDataSerializable() throws Exception {
    try {
      TestSerializableVariable originalSerializable = new TestSerializableVariable();
      originalSerializable.setSomeField("This is some field");

      // Test variable behaviour on standalone tasks
      Task task = taskService.newTask();
      taskService.saveTask(task);
      taskService.setVariableLocal(task.getId(), "localTaskVariable", originalSerializable);

      ClientResource client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE_DATA, task.getId(), "localTaskVariable"));
      client.get();
      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

      // Read the serializable from the stream
      ObjectInputStream stream =
          new ObjectInputStream(client.getResponse().getEntity().getStream());
      Object readSerializable = stream.readObject();
      assertNotNull(readSerializable);
      assertTrue(readSerializable instanceof TestSerializableVariable);
      assertEquals(
          "This is some field", ((TestSerializableVariable) readSerializable).getSomeField());
      assertEquals(MediaType.APPLICATION_JAVA_OBJECT.getName(), getMediaType(client));
    } finally {
      // Clean adhoc-tasks even if test fails
      List<Task> tasks = taskService.createTaskQuery().list();
      for (Task task : tasks) {
        taskService.deleteTask(task.getId(), true);
      }
    }
  }
  /** Test getting a task variable. GET runtime/tasks/{taskId}/variables/{variableName}/data */
  public void testGetTaskVariableData() throws Exception {
    try {
      // Test variable behaviour on standalone tasks
      Task task = taskService.newTask();
      taskService.saveTask(task);
      taskService.setVariableLocal(
          task.getId(), "localTaskVariable", "This is a binary piece of text".getBytes());

      // Force content-type to TEXT_PLAIN to make sure this is ignored and application-octect-stream
      // is always returned
      ClientResource client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE_DATA, task.getId(), "localTaskVariable"));
      client.get(MediaType.TEXT_PLAIN);

      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());
      String actualResponseBytesAsText = client.getResponse().getEntityAsText();
      assertEquals("This is a binary piece of text", actualResponseBytesAsText);
      assertEquals(MediaType.APPLICATION_OCTET_STREAM.getName(), getMediaType(client));
    } finally {
      // Clean adhoc-tasks even if test fails
      List<Task> tasks = taskService.createTaskQuery().list();
      for (Task task : tasks) {
        taskService.deleteTask(task.getId(), true);
      }
    }
  }
  /** Test getting a task variable. GET runtime/tasks/{taskId}/variables/{variableName}/data */
  public void testGetTaskVariableDataForIllegalVariables() throws Exception {
    try {
      // Test variable behaviour on standalone tasks
      Task task = taskService.newTask();
      taskService.saveTask(task);
      taskService.setVariableLocal(
          task.getId(), "localTaskVariable", "this is a plain string variable");

      // Try getting data for non-binary variable
      ClientResource client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE_DATA, task.getId(), "localTaskVariable"));
      try {
        client.get();
        fail("Exception expected");
      } catch (ResourceException expected) {
        assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
        assertEquals(
            "The variable does not have a binary data stream.",
            expected.getStatus().getDescription());
      }

      // Try getting data for unexisting property
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE_DATA, task.getId(), "unexistingVariable"));
      try {
        client.get();
        fail("Exception expected");
      } catch (ResourceException expected) {
        assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
        assertEquals(
            "Task '" + task.getId() + "' doesn't have a variable with name: 'unexistingVariable'.",
            expected.getStatus().getDescription());
      }

    } finally {
      // Clean adhoc-tasks even if test fails
      List<Task> tasks = taskService.createTaskQuery().list();
      for (Task task : tasks) {
        taskService.deleteTask(task.getId(), true);
      }
    }
  }
  /** Test getting a task variable. GET runtime/tasks/{taskId}/variables/{variableName} */
  @Deployment
  public void testGetTaskVariable() throws Exception {
    try {
      // Test variable behaviour on standalone tasks
      Task task = taskService.newTask();
      taskService.saveTask(task);
      taskService.setVariableLocal(task.getId(), "localTaskVariable", "localValue");

      ClientResource client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE, task.getId(), "localTaskVariable"));
      Representation response = client.get();
      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

      JsonNode responseNode = objectMapper.readTree(response.getStream());
      assertNotNull(responseNode);
      assertEquals("local", responseNode.get("scope").asText());
      assertEquals("localValue", responseNode.get("value").asText());
      assertEquals("localTaskVariable", responseNode.get("name").asText());
      assertEquals("string", responseNode.get("type").asText());

      // Test variable behaviour for a process-task
      ProcessInstance processInstance =
          runtimeService.startProcessInstanceByKey(
              "oneTaskProcess",
              Collections.singletonMap("sharedVariable", (Object) "processValue"));
      Task processTask =
          taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

      taskService.setVariableLocal(processTask.getId(), "sharedVariable", "taskValue");

      // ANY scope, local should get precedence
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE, processTask.getId(), "sharedVariable"));
      response = client.get();
      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

      responseNode = objectMapper.readTree(response.getStream());
      assertNotNull(responseNode);
      assertEquals("local", responseNode.get("scope").asText());
      assertEquals("taskValue", responseNode.get("value").asText());
      assertEquals("sharedVariable", responseNode.get("name").asText());
      assertEquals("string", responseNode.get("type").asText());

      // LOCAL scope
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                      RestUrls.URL_TASK_VARIABLE, processTask.getId(), "sharedVariable")
                  + "?scope=local");
      response = client.get();
      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

      responseNode = objectMapper.readTree(response.getStream());
      assertNotNull(responseNode);
      assertEquals("local", responseNode.get("scope").asText());
      assertEquals("taskValue", responseNode.get("value").asText());
      assertEquals("sharedVariable", responseNode.get("name").asText());
      assertEquals("string", responseNode.get("type").asText());

      // GLOBAL scope
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                      RestUrls.URL_TASK_VARIABLE, processTask.getId(), "sharedVariable")
                  + "?scope=global");
      response = client.get();
      assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

      responseNode = objectMapper.readTree(response.getStream());
      assertNotNull(responseNode);
      assertEquals("global", responseNode.get("scope").asText());
      assertEquals("processValue", responseNode.get("value").asText());
      assertEquals("sharedVariable", responseNode.get("name").asText());
      assertEquals("string", responseNode.get("type").asText());

      // Illegal scope
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                      RestUrls.URL_TASK_VARIABLE, processTask.getId(), "sharedVariable")
                  + "?scope=illegal");
      try {
        response = client.get();
        fail("Exception expected");
      } catch (ResourceException expected) {
        assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
        assertEquals("Invalid variable scope: 'illegal'", expected.getStatus().getDescription());
      }

      // Unexisting task
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE, "unexisting", "sharedVariable"));
      try {
        response = client.get();
        fail("Exception expected");
      } catch (ResourceException expected) {
        assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
        assertEquals("task unexisting doesn't exist", expected.getStatus().getDescription());
      }

      // Unexisting variable
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE, processTask.getId(), "unexistingVariable"));
      try {
        response = client.get();
        fail("Exception expected");
      } catch (ResourceException expected) {
        assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
        assertEquals(
            "Task '"
                + processTask.getId()
                + "' doesn't have a variable with name: 'unexistingVariable'.",
            expected.getStatus().getDescription());
      }

    } finally {
      // Clean adhoc-tasks even if test fails
      List<Task> tasks = taskService.createTaskQuery().list();
      for (Task task : tasks) {
        if (task.getExecutionId() == null) {
          taskService.deleteTask(task.getId(), true);
        }
      }
    }
  }
  /**
   * Test updating a single task variable in all scopes, including "not found" check.
   *
   * <p>PUT runtime/tasks/{taskId}/variables/{variableName}
   */
  @Deployment
  public void testUpdateTaskVariable() throws Exception {
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey(
            "oneTaskProcess",
            Collections.singletonMap("overlappingVariable", (Object) "processValue"));
    Task task =
        taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    taskService.setVariableLocal(task.getId(), "overlappingVariable", "taskValue");

    // Update variable without scope, local should be presumed -> local updated and global should be
    // retained
    ObjectNode requestNode = objectMapper.createObjectNode();
    requestNode.put("name", "overlappingVariable");
    requestNode.put("value", "updatedLocalValue");
    requestNode.put("type", "string");

    ClientResource client =
        getAuthenticatedClient(
            RestUrls.createRelativeResourceUrl(
                RestUrls.URL_TASK_VARIABLE, task.getId(), "overlappingVariable"));
    Representation response = client.put(requestNode);
    assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

    JsonNode responseNode = objectMapper.readTree(response.getStream());
    assertNotNull(responseNode);
    assertEquals("updatedLocalValue", responseNode.get("value").asText());
    assertEquals("local", responseNode.get("scope").asText());
    // Check local value is changed in engine and global one remains unchanged
    assertEquals(
        "updatedLocalValue", taskService.getVariableLocal(task.getId(), "overlappingVariable"));
    assertEquals(
        "processValue", runtimeService.getVariable(task.getExecutionId(), "overlappingVariable"));

    // Update variable in local scope
    response.release();
    requestNode = objectMapper.createObjectNode();
    requestNode.put("name", "overlappingVariable");
    requestNode.put("value", "updatedLocalValueOnceAgain");
    requestNode.put("type", "string");
    requestNode.put("scope", "local");
    response = client.put(requestNode);
    assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

    responseNode = objectMapper.readTree(response.getStream());
    assertNotNull(responseNode);
    assertEquals("updatedLocalValueOnceAgain", responseNode.get("value").asText());
    assertEquals("local", responseNode.get("scope").asText());
    // Check local value is changed in engine and global one remains unchanged
    assertEquals(
        "updatedLocalValueOnceAgain",
        taskService.getVariableLocal(task.getId(), "overlappingVariable"));
    assertEquals(
        "processValue", runtimeService.getVariable(task.getExecutionId(), "overlappingVariable"));

    // Update variable in global scope
    response.release();
    requestNode = objectMapper.createObjectNode();
    requestNode.put("name", "overlappingVariable");
    requestNode.put("value", "updatedInGlobalScope");
    requestNode.put("type", "string");
    requestNode.put("scope", "global");
    response = client.put(requestNode);
    assertEquals(Status.SUCCESS_OK, client.getResponse().getStatus());

    responseNode = objectMapper.readTree(response.getStream());
    assertNotNull(responseNode);
    assertEquals("updatedInGlobalScope", responseNode.get("value").asText());
    assertEquals("global", responseNode.get("scope").asText());
    // Check global value is changed in engine and local one remains unchanged
    assertEquals(
        "updatedLocalValueOnceAgain",
        taskService.getVariableLocal(task.getId(), "overlappingVariable"));
    assertEquals(
        "updatedInGlobalScope",
        runtimeService.getVariable(task.getExecutionId(), "overlappingVariable"));

    // Try updating with mismatch between URL and body variableName unexisting property
    try {
      requestNode.put("name", "unexistingVariable");
      client.put(requestNode);
      fail("Exception expected");
    } catch (ResourceException expected) {
      assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
      assertEquals(
          "Variable name in the body should be equal to the name used in the requested URL.",
          expected.getStatus().getDescription());
    }

    // Try updating unexisting property
    try {
      client =
          getAuthenticatedClient(
              RestUrls.createRelativeResourceUrl(
                  RestUrls.URL_TASK_VARIABLE, task.getId(), "unexistingVariable"));
      requestNode.put("name", "unexistingVariable");
      client.put(requestNode);
      fail("Exception expected");
    } catch (ResourceException expected) {
      assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
      assertEquals(
          "Task '" + task.getId() + "' doesn't have a variable with name: 'unexistingVariable'.",
          expected.getStatus().getDescription());
    }
  }
  /**
   * Test deleting a single task variable in all scopes, including "not found" check.
   *
   * <p>DELETE runtime/tasks/{taskId}/variables/{variableName}
   */
  @Deployment
  public void testDeleteTaskVariable() throws Exception {
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey(
            "oneTaskProcess",
            Collections.singletonMap("overlappingVariable", (Object) "processValue"));
    Task task =
        taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    taskService.setVariableLocal(task.getId(), "overlappingVariable", "taskValue");
    taskService.setVariableLocal(task.getId(), "anotherTaskVariable", "taskValue");

    // Delete variable without scope, local should be presumed -> local removed and global should be
    // retained
    ClientResource client =
        getAuthenticatedClient(
            RestUrls.createRelativeResourceUrl(
                RestUrls.URL_TASK_VARIABLE, task.getId(), "overlappingVariable"));
    Representation response = client.delete();
    assertEquals(Status.SUCCESS_NO_CONTENT, client.getResponse().getStatus());
    assertEquals(0L, response.getSize());
    assertFalse(taskService.hasVariableLocal(task.getId(), "overlappingVariable"));
    assertTrue(taskService.hasVariable(task.getId(), "overlappingVariable"));

    // Delete local scope variable
    client.release();
    client =
        getAuthenticatedClient(
            RestUrls.createRelativeResourceUrl(
                    RestUrls.URL_TASK_VARIABLE, task.getId(), "anotherTaskVariable")
                + "?scope=local");
    response = client.delete();
    assertEquals(Status.SUCCESS_NO_CONTENT, client.getResponse().getStatus());
    assertEquals(0L, response.getSize());
    assertFalse(taskService.hasVariableLocal(task.getId(), "anotherTaskVariable"));

    // Delete global scope variable
    assertTrue(taskService.hasVariable(task.getId(), "overlappingVariable"));
    client.release();
    client =
        getAuthenticatedClient(
            RestUrls.createRelativeResourceUrl(
                    RestUrls.URL_TASK_VARIABLE, task.getId(), "overlappingVariable")
                + "?scope=global");
    response = client.delete();
    assertEquals(Status.SUCCESS_NO_CONTENT, client.getResponse().getStatus());
    assertEquals(0L, response.getSize());
    assertFalse(taskService.hasVariable(task.getId(), "overlappingVariable"));

    // Run the same delete again, variable is not there so 404 should be returned
    client.release();
    try {
      client.delete();
      fail("Exception expected");
    } catch (ResourceException expected) {
      assertEquals(Status.CLIENT_ERROR_NOT_FOUND, expected.getStatus());
      assertEquals(
          "Task '"
              + task.getId()
              + "' doesn't have a variable 'overlappingVariable' in scope global",
          expected.getStatus().getDescription());
    }
  }
  /** Test querying historic variable instance. POST query/historic-variable-instances */
  @Deployment
  public void testQueryVariableInstances() throws Exception {
    HashMap<String, Object> processVariables = new HashMap<String, Object>();
    processVariables.put("stringVar", "Azerty");
    processVariables.put("intVar", 67890);
    processVariables.put("booleanVar", false);

    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey("oneTaskProcess", processVariables);
    Task task =
        taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    taskService.setVariableLocal(task.getId(), "taskVariable", "test");

    ProcessInstance processInstance2 =
        runtimeService.startProcessInstanceByKey("oneTaskProcess", processVariables);

    String url = RestUrls.createRelativeResourceUrl(RestUrls.URL_HISTORIC_VARIABLE_INSTANCE_QUERY);

    ObjectNode requestNode = objectMapper.createObjectNode();
    requestNode.put("variableName", "stringVar");
    assertResultsPresentInDataResponse(url, requestNode, 2, "stringVar", "Azerty");

    requestNode = objectMapper.createObjectNode();
    requestNode.put("variableName", "booleanVar");
    assertResultsPresentInDataResponse(url, requestNode, 2, "booleanVar", false);

    requestNode = objectMapper.createObjectNode();
    requestNode.put("variableName", "booleanVar2");
    assertResultsPresentInDataResponse(url, requestNode, 0, null, null);

    requestNode = objectMapper.createObjectNode();
    requestNode.put("processInstanceId", processInstance.getId());
    assertResultsPresentInDataResponse(url, requestNode, 4, "taskVariable", "test");

    requestNode = objectMapper.createObjectNode();
    requestNode.put("processInstanceId", processInstance.getId());
    requestNode.put("excludeTaskVariables", true);
    assertResultsPresentInDataResponse(url, requestNode, 3, "intVar", 67890);

    requestNode = objectMapper.createObjectNode();
    requestNode.put("processInstanceId", processInstance2.getId());
    assertResultsPresentInDataResponse(url, requestNode, 3, "stringVar", "Azerty");

    requestNode = objectMapper.createObjectNode();
    requestNode.put("taskId", task.getId());
    assertResultsPresentInDataResponse(url, requestNode, 1, "taskVariable", "test");

    requestNode = objectMapper.createObjectNode();
    requestNode.put("taskId", task.getId());
    requestNode.put("variableName", "booleanVar");
    assertResultsPresentInDataResponse(url, requestNode, 0, null, null);

    requestNode = objectMapper.createObjectNode();
    requestNode.put("variableNameLike", "%Var");
    assertResultsPresentInDataResponse(url, requestNode, 6, "stringVar", "Azerty");

    requestNode = objectMapper.createObjectNode();
    requestNode.put("variableNameLike", "%Var2");
    assertResultsPresentInDataResponse(url, requestNode, 0, null, null);

    requestNode = objectMapper.createObjectNode();
    ArrayNode variableArray = objectMapper.createArrayNode();
    ObjectNode variableNode = objectMapper.createObjectNode();
    variableArray.add(variableNode);
    requestNode.put("variables", variableArray);
    variableNode.put("name", "stringVar");
    variableNode.put("value", "Azerty");
    variableNode.put("operation", "equals");
    assertResultsPresentInDataResponse(url, requestNode, 2, "stringVar", "Azerty");

    variableNode.removeAll();
    requestNode.put("variables", variableArray);
    variableNode.put("name", "taskVariable");
    variableNode.put("value", "test");
    variableNode.put("operation", "equals");
    assertResultsPresentInDataResponse(url, requestNode, 1, "taskVariable", "test");

    variableNode.removeAll();
    requestNode.put("variables", variableArray);
    variableNode.put("name", "taskVariable");
    variableNode.put("value", "test");
    variableNode.put("operation", "notEquals");
    assertErrorResult(url, requestNode, Status.CLIENT_ERROR_BAD_REQUEST);
  }
  @Deployment(
      resources = {
        "org/activiti/rest/api/management/JobCollectionResourceTest.testTimerProcess.bpmn20.xml"
      })
  public void testGetJobs() throws Exception {
    Calendar hourAgo = Calendar.getInstance();
    hourAgo.add(Calendar.HOUR, -1);

    Calendar inAnHour = Calendar.getInstance();
    inAnHour.add(Calendar.HOUR, 1);

    // Start process, forcing error on job-execution
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey(
            "timerProcess", Collections.singletonMap("error", (Object) Boolean.TRUE));

    Job timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .timers()
            .singleResult();
    assertNotNull(timerJob);

    for (int i = 0; i < timerJob.getRetries(); i++) {
      // Force execution of job until retries are exhausted
      try {
        managementService.executeJob(timerJob.getId());
        fail();
      } catch (ActivitiException expected) {
        // Ignore, we expect the exception
      }
    }
    timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .timers()
            .singleResult();
    assertEquals(0, timerJob.getRetries());

    // Fetch the async-job (which has retries left)
    Job asyncJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .withRetriesLeft()
            .singleResult();

    // Test fetching all jobs
    String url = RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION);
    assertResultsPresentInDataResponse(url, asyncJob.getId(), timerJob.getId());

    // Fetch using job-id
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION) + "?id=" + asyncJob.getId();
    assertResultsPresentInDataResponse(url, asyncJob.getId());

    // Fetch using processInstanceId
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?processInstanceId="
            + processInstance.getId();
    assertResultsPresentInDataResponse(url, asyncJob.getId(), timerJob.getId());

    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?processInstanceId=unexisting";
    assertResultsPresentInDataResponse(url);

    // Fetch using executionId
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?executionId="
            + asyncJob.getExecutionId();
    assertResultsPresentInDataResponse(url, asyncJob.getId());

    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?executionId="
            + timerJob.getExecutionId();
    assertResultsPresentInDataResponse(url, timerJob.getId());

    // Fetch using processDefinitionId
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?processDefinitionId="
            + processInstance.getProcessDefinitionId();
    assertResultsPresentInDataResponse(url, asyncJob.getId(), timerJob.getId());

    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?processDefinitionId=unexisting";
    assertResultsPresentInDataResponse(url);

    // Fetch using withRetriesLeft
    url = RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION) + "?withRetriesLeft=true";
    assertResultsPresentInDataResponse(url, asyncJob.getId());

    // Fetch using executable
    url = RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION) + "?executable=true";
    assertResultsPresentInDataResponse(url, asyncJob.getId());

    // Fetch using timers only
    url = RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION) + "?timersOnly=true";
    assertResultsPresentInDataResponse(url, timerJob.getId());

    // Combining messagesOnly with timersOnly should result in exception
    ClientResource client =
        getAuthenticatedClient(
            RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
                + "?timersOnly=true&messagesOnly=true");
    try {
      client.get();
      fail("Exception expected");
    } catch (ResourceException expected) {
      assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, expected.getStatus());
      assertEquals(
          "Only one of 'timersOnly' or 'messagesOnly' can be provided.",
          expected.getStatus().getDescription());
    }

    // Fetch using dueBefore
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?dueBefore="
            + getISODateString(inAnHour.getTime());
    assertResultsPresentInDataResponse(url, timerJob.getId());

    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?dueBefore="
            + getISODateString(hourAgo.getTime());
    assertResultsPresentInDataResponse(url);

    // Fetch using dueAfter
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?dueAfter="
            + getISODateString(hourAgo.getTime());
    assertResultsPresentInDataResponse(url, timerJob.getId());

    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?dueAfter="
            + getISODateString(inAnHour.getTime());
    assertResultsPresentInDataResponse(url);

    // Fetch using withException
    url = RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION) + "?withException=true";
    assertResultsPresentInDataResponse(url, timerJob.getId());

    // Fetch with exceptionMessage
    url =
        RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION)
            + "?exceptionMessage="
            + timerJob.getExceptionMessage();
    assertResultsPresentInDataResponse(url, timerJob.getId());

    // Fetch with empty exceptionMessage
    url = RestUrls.createRelativeResourceUrl(RestUrls.URL_JOB_COLLECTION) + "?exceptionMessage=";
    assertResultsPresentInDataResponse(url);
  }