@Test
public void testConfigTransferCopy() throws Exception {

  makeUpgradeCluster();
  Cluster c = clusters.getCluster("c1");
  assertEquals(1, c.getConfigsByType("zoo.cfg").size());
  c.setDesiredStackVersion(HDP_220_STACK);
  Config config = cf.createNew(c, "zoo.cfg", "version2", new HashMap<String, String>() {{
        put("initLimit", "10");
        put("copyIt", "10");
        put("moveIt", "10");
        put("deleteIt", "10");
      }}, new HashMap<String, Map<String,String>>());
  c.addDesiredConfig("user", Collections.singleton(config));
  assertEquals(2, c.getConfigsByType("zoo.cfg").size());
  List<ConfigurationKeyValue> configurations = new ArrayList<>();
  ConfigurationKeyValue keyValue = new ConfigurationKeyValue();
  configurations.add(keyValue);
  keyValue.key = "initLimit";
  keyValue.value = "11";
  Map<String, String> commandParams = new HashMap<>();
  commandParams.put("upgrade_direction", "upgrade");
  commandParams.put("version", HDP_2_2_0_1);
  commandParams.put("clusterName", "c1");
  commandParams.put(ConfigureTask.PARAMETER_CONFIG_TYPE, "zoo.cfg");
  commandParams.put(ConfigureTask.PARAMETER_KEY_VALUE_PAIRS, new Gson().toJson(configurations));
  // normal copy
  List<Transfer> transfers = new ArrayList<>();
  Transfer transfer = new Transfer();
  transfer.operation = TransferOperation.COPY;
  transfer.fromKey = "copyIt";
  transfer.toKey = "copyKey";
  transfers.add(transfer);
  // copy with default
  transfer = new Transfer();
  transfer.operation = TransferOperation.COPY;
  transfer.fromKey = "copiedFromMissingKeyWithDefault";
  transfer.toKey = "copiedToMissingKeyWithDefault";
  transfer.defaultValue = "defaultValue";
  transfers.add(transfer);
  // normal move
  transfer = new Transfer();
  transfer.operation = TransferOperation.MOVE;
  transfer.fromKey = "moveIt";
  transfer.toKey = "movedKey";
  transfers.add(transfer);
  // move with default
  transfer = new Transfer();
  transfer.operation = TransferOperation.MOVE;
  transfer.fromKey = "movedFromKeyMissingWithDefault";
  transfer.toKey = "movedToMissingWithDefault";
  transfer.defaultValue = "defaultValue2";
  transfer.mask = true;
  transfers.add(transfer);
  transfer = new Transfer();
  transfer.operation = TransferOperation.DELETE;
  transfer.deleteKey = "deleteIt";
  transfers.add(transfer);
  commandParams.put(ConfigureTask.PARAMETER_TRANSFERS, new Gson().toJson(transfers));
  ExecutionCommand executionCommand = new ExecutionCommand();
  executionCommand.setCommandParams(commandParams);
  executionCommand.setClusterName("c1");
  executionCommand.setRoleParams(new HashMap<String, String>());
  executionCommand.getRoleParams().put(ServerAction.ACTION_USER_NAME, "username");
  HostRoleCommand hostRoleCommand = hostRoleCommandFactory.create(null, null,
      null, null);
  hostRoleCommand.setExecutionCommandWrapper(new ExecutionCommandWrapper(
      executionCommand));
  action.setExecutionCommand(executionCommand);
  action.setHostRoleCommand(hostRoleCommand);
  CommandReport report = action.execute(null);
  assertNotNull(report);
  assertEquals(3, c.getConfigsByType("zoo.cfg").size());
  config = c.getDesiredConfigByType("zoo.cfg");
  assertNotNull(config);
  assertFalse("version2".equals(config.getTag()));
  Map<String, String> map = config.getProperties();
  assertEquals("11", map.get("initLimit"));
  assertEquals("10", map.get("copyIt"));
  assertTrue(map.containsKey("copyKey"));
  assertEquals(map.get("copyIt"), map.get("copyKey"));
  assertFalse(map.containsKey("moveIt"));
  assertTrue(map.containsKey("movedKey"));
  assertFalse(map.containsKey("deletedKey"));
  assertTrue(map.containsKey("copiedToMissingKeyWithDefault"));
  assertEquals("defaultValue", map.get("copiedToMissingKeyWithDefault"));
  assertTrue(map.containsKey("movedToMissingWithDefault"));
  assertEquals("defaultValue2", map.get("movedToMissingWithDefault"));
  transfers.clear();
  transfer = new Transfer();
  transfer.operation = TransferOperation.DELETE;
  transfer.deleteKey = "*";
  transfer.preserveEdits = true;
  transfer.keepKeys.add("copyKey");
  // The below key should be ignored/not added as it doesn't exist originally as part of transfer.
  transfer.keepKeys.add("keyNotExisting");
  // The 'null' passed as part of key should be ignored as part of transfer operation.
  transfer.keepKeys.add(null);
  transfers.add(transfer);
  commandParams.put(ConfigureTask.PARAMETER_TRANSFERS, new Gson().toJson(transfers));
  report = action.execute(null);
  assertNotNull(report);
  assertEquals(4, c.getConfigsByType("zoo.cfg").size());
  config = c.getDesiredConfigByType("zoo.cfg");
  map = config.getProperties();
  assertEquals(6, map.size());
  assertTrue(map.containsKey("initLimit")); // it just changed to 11 from 10
  assertTrue(map.containsKey("copyKey")); // is new
  // Below two keys should not have been added in the map.
  assertFalse(map.containsKey("keyNotExisting"));
  assertFalse(map.containsKey(null));
}