@Before
  public void setup() throws Exception {
    MockitoAnnotations.initMocks(this);
    storageCmd = PowerMockito.mock(CopyCommand.class);
    doReturn(context).when(_resource).getServiceContext(null);
    when(cmd.getVirtualMachine()).thenReturn(vmSpec);

    when(storageCmd.getSrcTO()).thenReturn(srcDataTO);
    when(srcDataTO.getDataStore()).thenReturn(srcDataNfsTO);
    when(srcDataNfsTO.getNfsVersion()).thenReturn(NFS_VERSION);
    when(videoCard.getVideoRamSizeInKB()).thenReturn(VIDEO_CARD_MEMORY_SIZE);
    when(volume.getPath()).thenReturn(VOLUME_PATH);

    when(storageCmd.getDestTO()).thenReturn(destDataTO);
    when(destDataTO.getHypervisorType()).thenReturn(HypervisorType.VMware);
    when(destDataTO.getDataStore()).thenReturn(destDataStoreTO);
    when(destDataStoreTO.isFullCloneFlag()).thenReturn(FULL_CLONE_FLAG);
    when(volume.getPath()).thenReturn(VOLUME_PATH);
    when(vmSpec.getDetails()).thenReturn(specsArray);

    when(vmMo.getContext()).thenReturn(context);
    when(vmMo.getRunningHost()).thenReturn(host);
    when(host.getMor()).thenReturn(hostRef);
    when(context.getVimClient()).thenReturn(client);
    when(client.getMoRefProp(hostRef, "parent")).thenReturn(computeRef);
    when(client.getMoRefProp(computeRef, "environmentBrowser")).thenReturn(envRef);
    when(context.getService()).thenReturn(vimService);
    when(vimService.queryTargetCapabilities(envRef, hostRef)).thenReturn(hostCapability);
    when(hostCapability.isNestedHVSupported()).thenReturn(true);
  }
  @Override
  protected Answer execute(CopyCommand cmd) {
    DataTO srcData = cmd.getSrcTO();
    DataTO destData = cmd.getDestTO();
    DataStoreTO srcDataStore = srcData.getDataStore();
    DataStoreTO destDataStore = destData.getDataStore();
    // if copied between s3 and nfs cache, go to resource
    boolean needDelegation = false;
    if (destDataStore instanceof NfsTO && destDataStore.getRole() == DataStoreRole.ImageCache) {
      if (srcDataStore instanceof S3TO || srcDataStore instanceof SwiftTO) {
        needDelegation = true;
      }
    }

    if (srcDataStore.getRole() == DataStoreRole.ImageCache
        && destDataStore.getRole() == DataStoreRole.Image) {
      // need to take extra processing for vmware, such as packing to ova, before sending to S3
      if (srcData.getObjectType() == DataObjectType.VOLUME) {
        NfsTO cacheStore = (NfsTO) srcDataStore;
        String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion);
        VolumeObjectTO vol = (VolumeObjectTO) srcData;
        String path = vol.getPath();
        int index = path.lastIndexOf(File.separator);
        String name = path.substring(index + 1);
        storageManager.createOva(parentPath + File.separator + path, name);
        vol.setPath(path + File.separator + name + ".ova");
      } else if (srcData.getObjectType() == DataObjectType.TEMPLATE) {
        // sync template from NFS cache to S3 in NFS migration to S3 case
        storageManager.createOvaForTemplate((TemplateObjectTO) srcData);
      } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) {
        // pack ova first
        // sync snapshot from NFS cache to S3 in NFS migration to S3 case
        String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), _nfsVersion);
        SnapshotObjectTO snap = (SnapshotObjectTO) srcData;
        String path = snap.getPath();
        int index = path.lastIndexOf(File.separator);
        String name = path.substring(index + 1);
        String snapDir = path.substring(0, index);
        storageManager.createOva(parentPath + File.separator + snapDir, name);
        if (destData.getObjectType() == DataObjectType.TEMPLATE) {
          // create template from snapshot on src at first, then copy it to s3
          TemplateObjectTO cacheTemplate = (TemplateObjectTO) destData;
          cacheTemplate.setDataStore(srcDataStore);
          CopyCmdAnswer answer = (CopyCmdAnswer) processor.createTemplateFromSnapshot(cmd);
          if (!answer.getResult()) {
            return answer;
          }
          cacheTemplate.setDataStore(destDataStore);
          TemplateObjectTO template = (TemplateObjectTO) answer.getNewData();
          template.setDataStore(srcDataStore);
          CopyCommand newCmd =
              new CopyCommand(template, destData, cmd.getWait(), cmd.executeInSequence());
          Answer result = storageResource.defaultAction(newCmd);
          // clean up template data on staging area
          try {
            DeleteCommand deleteCommand = new DeleteCommand(template);
            storageResource.defaultAction(deleteCommand);
          } catch (Exception e) {
            s_logger.debug("Failed to clean up staging area:", e);
          }
          return result;
        }
      }
      needDelegation = true;
    }

    if (srcData.getObjectType() == DataObjectType.SNAPSHOT
        && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
      // for back up snapshot, we need to do backup to cache, then to object store if object store
      // is used.
      if (cmd.getCacheTO() != null) {
        cmd.setDestTO(cmd.getCacheTO());

        CopyCmdAnswer answer = (CopyCmdAnswer) processor.backupSnapshot(cmd);
        if (!answer.getResult()) {
          return answer;
        }
        NfsTO cacheStore = (NfsTO) cmd.getCacheTO().getDataStore();
        String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion);
        SnapshotObjectTO newSnapshot = (SnapshotObjectTO) answer.getNewData();
        String path = newSnapshot.getPath();
        int index = path.lastIndexOf(File.separator);
        String name = path.substring(index + 1);
        String dir = path.substring(0, index);
        storageManager.createOva(parentPath + File.separator + dir, name);
        newSnapshot.setPath(newSnapshot.getPath() + ".ova");
        newSnapshot.setDataStore(cmd.getCacheTO().getDataStore());
        CopyCommand newCmd =
            new CopyCommand(newSnapshot, destData, cmd.getWait(), cmd.executeInSequence());
        Answer result = storageResource.defaultAction(newCmd);

        // clean up data on staging area
        try {
          newSnapshot.setPath(path);
          DeleteCommand deleteCommand = new DeleteCommand(newSnapshot);
          storageResource.defaultAction(deleteCommand);
        } catch (Exception e) {
          s_logger.debug("Failed to clean up staging area:", e);
        }
        return result;
      }
    }

    if (needDelegation) {
      return storageResource.defaultAction(cmd);
    } else {
      return super.execute(cmd);
    }
  }