@Test(dataProvider = "ImmutableFieldNames", expectedExceptions = DcpRuntimeException.class)
    public void testInvalidPatchImmutableFieldChanged(String fieldName) throws Throwable {
      InitializeDeploymentMigrationWorkflowService.State startState =
          buildValidStartState(null, null);
      Operation startOperation =
          testHost.startServiceSynchronously(
              initializeDeploymentMigrationWorkflowService, startState);
      assertThat(startOperation.getStatusCode(), is(200));
      serviceCreated = true;

      InitializeDeploymentMigrationWorkflowService.State patchState =
          buildValidPatchState(
              TaskState.TaskStage.STARTED,
              InitializeDeploymentMigrationWorkflowService.TaskState.SubStage
                  .PAUSE_DESTINATION_SYSTEM);

      Field declaredField = patchState.getClass().getDeclaredField(fieldName);
      if (declaredField.getType() == Integer.class) {
        declaredField.set(patchState, new Integer(0));
      } else if (declaredField.getType() == Set.class) {
        declaredField.set(patchState, new HashSet<>());
      } else {
        declaredField.set(patchState, declaredField.getType().newInstance());
      }

      Operation patchOperation =
          Operation.createPatch(UriUtils.buildUri(testHost, TestHost.SERVICE_URI))
              .setBody(patchState);

      testHost.sendRequestAndWait(patchOperation);
    }
 @Test(dataProvider = "RequiredFieldNames", expectedExceptions = DcpRuntimeException.class)
 public void testInvalidStartStateMissingRequiredField(String fieldName) throws Throwable {
   InitializeDeploymentMigrationWorkflowService.State startState =
       buildValidStartState(null, null);
   startState.getClass().getDeclaredField(fieldName).set(startState, null);
   startService(startState);
 }
  /**
   * This method creates a new State object which is sufficient to create a new
   * FinishDeploymentWorkflowService instance.
   */
  private InitializeDeploymentMigrationWorkflowService.State buildValidStartState(
      @Nullable InitializeDeploymentMigrationWorkflowService.TaskState.TaskStage startStage,
      @Nullable InitializeDeploymentMigrationWorkflowService.TaskState.SubStage startSubStage)
      throws Throwable {
    InitializeDeploymentMigrationWorkflowService.State startState =
        new InitializeDeploymentMigrationWorkflowService.State();
    startState.controlFlags = ControlFlags.CONTROL_FLAG_OPERATION_PROCESSING_DISABLED;
    startState.sourceLoadBalancerAddress = "lbLink1";
    startState.destinationDeploymentId = "deployment1";
    startState.taskPollDelay = 1;

    if (null != startStage) {
      startState.taskState = new InitializeDeploymentMigrationWorkflowService.TaskState();
      startState.taskState.stage = startStage;
      startState.taskState.subStage = startSubStage;

      if (TaskState.TaskStage.STARTED == startStage) {
        switch (startSubStage) {
          case CONTIONUS_MIGRATE_DATA:
          case UPLOAD_VIBS:
            startState.sourceZookeeperQuorum = "quorum";
            // fall through
          case PAUSE_DESTINATION_SYSTEM:
            startState.sourceDeploymentId = "deployment1";
            break;
        }
      }
    }

    return startState;
  }
    @Test(dataProvider = "TerminalStartStages")
    public void testTerminalStartState(
        InitializeDeploymentMigrationWorkflowService.TaskState.TaskStage startStage,
        InitializeDeploymentMigrationWorkflowService.TaskState.SubStage startSubStage)
        throws Throwable {
      InitializeDeploymentMigrationWorkflowService.State startState =
          buildValidStartState(startStage, startSubStage);
      startState.controlFlags = null;
      startService(startState);

      InitializeDeploymentMigrationWorkflowService.State serviceState =
          testHost.getServiceState(InitializeDeploymentMigrationWorkflowService.State.class);

      assertThat(serviceState.taskState.stage, is(startStage));
      assertThat(serviceState.taskState.subStage, nullValue());
    }
    @BeforeClass
    public void setUpClass() throws Throwable {
      listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));

      startState =
          buildValidStartState(
              InitializeDeploymentMigrationWorkflowService.TaskState.TaskStage.CREATED, null);
      startState.controlFlags = null;
      startState.taskPollDelay = 10;

      sourceCloudStore =
          com.vmware.photon.controller.cloudstore.dcp.helpers.TestEnvironment.create(1);
      destinationCloudStore =
          com.vmware.photon.controller.cloudstore.dcp.helpers.TestEnvironment.create(1);

      FileUtils.deleteDirectory(storageDirectory);
      vibDirectory.mkdirs();
      TestHelper.createSourceFile(null, vibDirectory);
    }
    private void createTestEnvironment() throws Throwable {
      ZookeeperClientFactory zkFactory = mock(ZookeeperClientFactory.class);
      sourceEnvironment =
          new TestEnvironment.Builder()
              .listeningExecutorService(listeningExecutorService)
              .apiClientFactory(apiClientFactory)
              .cloudServerSet(sourceCloudStore.getServerSet())
              .hostCount(1)
              .build();

      destinationEnvironment =
          new TestEnvironment.Builder()
              .hostCount(1)
              .apiClientFactory(apiClientFactory)
              .cloudServerSet(destinationCloudStore.getServerSet())
              .httpFileServiceClientFactory(httpFileServiceClientFactory)
              .zookeeperServersetBuilderFactory(zkFactory)
              .build();

      ZookeeperClient zkBuilder = mock(ZookeeperClient.class);
      doReturn(zkBuilder).when(zkFactory).create();
      doReturn(
              Collections.singleton(
                  new InetSocketAddress(
                      "127.0.0.1", sourceEnvironment.getHosts()[0].getState().httpPort)))
          .when(zkBuilder)
          .getServers(Matchers.startsWith("127.0.0.1:2181"), eq("cloudstore"));

      ServiceHost sourceHost = sourceEnvironment.getHosts()[0];
      startState.sourceLoadBalancerAddress = sourceHost.getPublicUri().toString();

      TestHelper.createHostService(sourceCloudStore, Collections.singleton(UsageTag.MGMT.name()));
      TestHelper.createHostService(sourceCloudStore, Collections.singleton(UsageTag.CLOUD.name()));
      DeploymentService.State deploymentService =
          TestHelper.createDeploymentService(destinationCloudStore);
      startState.destinationDeploymentId =
          ServiceUtils.getIDFromDocumentSelfLink(deploymentService.documentSelfLink);
    }
  /**
   * This method creates a patch State object which is sufficient to patch a
   * InitializeDeploymentMigrationWorkflowService instance.
   */
  private InitializeDeploymentMigrationWorkflowService.State buildValidPatchState(
      TaskState.TaskStage patchStage,
      InitializeDeploymentMigrationWorkflowService.TaskState.SubStage patchSubStage) {

    InitializeDeploymentMigrationWorkflowService.State patchState =
        new InitializeDeploymentMigrationWorkflowService.State();
    patchState.taskState = new InitializeDeploymentMigrationWorkflowService.TaskState();
    patchState.taskState.stage = patchStage;
    patchState.taskState.subStage = patchSubStage;

    if (TaskState.TaskStage.STARTED == patchStage) {
      switch (patchSubStage) {
        case CONTIONUS_MIGRATE_DATA:
        case UPLOAD_VIBS:
          patchState.sourceZookeeperQuorum = "quorum";
          break;
        case PAUSE_DESTINATION_SYSTEM:
          patchState.sourceDeploymentId = "deployment1";
          break;
      }
    }

    return patchState;
  }