public PropertiesSnapshot updateWorkflowProperties(
      String workflowId, User author, Properties props, PropertiesUpdate update) {
    LOG.debug("Updating workflow properties for workflow id [{}]", workflowId);
    Checks.notNull(
        props, "properties changes to apply cannot be null for workflow [%s]", workflowId);
    return withMetricLogError(
        () ->
            withRetryableTransaction(
                conn -> {
                  WorkflowInfo workflowInfo = getWorkflowInfoForUpdate(conn, workflowId);
                  Checks.notNull(
                      workflowInfo.getPrevPropertiesSnapshot(),
                      "Cannot update workflow properties while the workflow [%s] does not exist",
                      workflowId);
                  PropertiesSnapshot snapshot =
                      updateWorkflowProps(
                          conn,
                          workflowId,
                          author,
                          System.currentTimeMillis(),
                          workflowInfo.getPrevPropertiesSnapshot(),
                          props,
                          update);

                  List<StatementPreparer> preparers = new ArrayList<>();
                  StringBuilder fields = prepareProperties(preparers, workflowId, snapshot);

                  long[] updateRes = executeTemplateUpdate(conn, fields, preparers);

                  if (updateRes != null) {
                    if (workflowInfo.getPrevActiveVersionId() != Constants.INACTIVE_VERSION_ID) {
                      updateWorkflowInfoForNextActiveWorkflow(
                          conn,
                          workflowId,
                          workflowInfo.getPrevActiveVersionId(),
                          workflowInfo,
                          snapshot);
                      addWorkflowTriggersIfNeeded(conn, workflowInfo);
                    }

                    MaestroJobEvent jobEvent = logToTimeline(conn, workflowId, snapshot);
                    publisher.publishOrThrow(
                        jobEvent, "Failed to publish maestro properties change job event.");
                  }
                  return snapshot;
                }),
        "updateWorkflowProperties",
        "Failed updating the properties for workflow [{}]",
        workflowId);
  }
@Test
  public void testInvalidWorkflowProperties() {
    AssertHelper.assertThrows(
        "cannot push a empty properties change for any workflow",
        NullPointerException.class,
        "properties changes to apply cannot be null for workflow",
        () ->
            workflowDao.updateWorkflowProperties(
                TEST_WORKFLOW_ID2, User.create("test"), null, PROPERTIES_UPDATE));

    AssertHelper.assertThrows(
        "cannot push a properties change for non-existing workflow",
        NullPointerException.class,
        "Cannot update workflow properties while the workflow",
        () ->
            workflowDao.updateWorkflowProperties(
                TEST_WORKFLOW_ID2, User.create("test"), new Properties(), PROPERTIES_UPDATE));
  }