@VisibleForTesting
  public static boolean updateMapInternal(BiMap<Integer, String> map,
      String mapName, String command, String regex,
      Map<Integer, Integer> staticMapping) throws IOException  {
    boolean updated = false;
    BufferedReader br = null;
    try {
      Process process = Runtime.getRuntime().exec(
          new String[] { "bash", "-c", command });
      br = new BufferedReader(
          new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
      String line = null;
      while ((line = br.readLine()) != null) {
        String[] nameId = line.split(regex);
        if ((nameId == null) || (nameId.length != 2)) {
          throw new IOException("Can't parse " + mapName + " list entry:" + line);
        }
        LOG.debug("add to " + mapName + "map:" + nameId[0] + " id:" + nameId[1]);
        // HDFS can't differentiate duplicate names with simple authentication
        final Integer key = staticMapping.get(parseId(nameId[1]));
        final String value = nameId[0];
        if (map.containsKey(key)) {
          final String prevValue = map.get(key);
          if (value.equals(prevValue)) {
            // silently ignore equivalent entries
            continue;
          }
          reportDuplicateEntry(
              "Got multiple names associated with the same id: ",
              key, value, key, prevValue);           
          continue;
        }
        if (map.containsValue(value)) {
          final Integer prevKey = map.inverse().get(value);
          reportDuplicateEntry(
              "Got multiple ids associated with the same name: ",
              key, value, prevKey, value);
          continue;
        }
        map.put(key, value);
        updated = true;
      }
      LOG.debug("Updated " + mapName + " map size: " + map.size());
      
    } catch (IOException e) {
      LOG.error("Can't update " + mapName + " map");
      throw e;
    } finally {
      if (br != null) {
        try {
          br.close();
        } catch (IOException e1) {
          LOG.error("Can't close BufferedReader of command result", e1);
        }
      }
    }
    return updated;
  }
@Test
  public void testStaticMapping() throws IOException {
    assumeNotWindows();
    Map<Integer, Integer> uidStaticMap = new PassThroughMap<Integer>();
    Map<Integer, Integer> gidStaticMap = new PassThroughMap<Integer>();
    
    uidStaticMap.put(11501, 10);
    gidStaticMap.put(497, 200);
    
    // Maps for id to name map
    BiMap<Integer, String> uMap = HashBiMap.create();
    BiMap<Integer, String> gMap = HashBiMap.create();
    
    String GET_ALL_USERS_CMD =
        "echo \"atm:x:1000:1000:Aaron T. Myers,,,:/home/atm:/bin/bash\n"
        + "hdfs:x:11501:10787:Grid Distributed File System:/home/hdfs:/bin/bash\""
        + " | cut -d: -f1,3";
    
    String GET_ALL_GROUPS_CMD = "echo \"hdfs:*:11501:hrt_hdfs\n"
        + "mapred:x:497\n"
        + "mapred2:x:498\""
        + " | cut -d: -f1,3";

    ShellBasedIdMapping.updateMapInternal(uMap, "user", GET_ALL_USERS_CMD, ":",
        uidStaticMap);
    ShellBasedIdMapping.updateMapInternal(gMap, "group", GET_ALL_GROUPS_CMD, ":",
        gidStaticMap);
    
    assertEquals("hdfs", uMap.get(10));
    assertEquals(10, (int)uMap.inverse().get("hdfs"));
    assertEquals("atm", uMap.get(1000));
    assertEquals(1000, (int)uMap.inverse().get("atm"));
    
    assertEquals("hdfs", gMap.get(11501));
    assertEquals(11501, (int)gMap.inverse().get("hdfs"));
    assertEquals("mapred", gMap.get(200));
    assertEquals(200, (int)gMap.inverse().get("mapred"));
    assertEquals("mapred2", gMap.get(498));
    assertEquals(498, (int)gMap.inverse().get("mapred2"));
  }