@ForAllEnvironments
  public void testLinkLastModificationTime() throws Exception {
    String baseDir = null;
    try {
      baseDir = mkTempAndRefreshParent(true);
      String linkName = "link";
      String fileName = "data";
      String script =
          "cd "
              + baseDir
              + "; "
              + "touch "
              + baseDir
              + "/"
              + fileName
              + ";"
              + "sleep 10;"
              + "ln -s "
              + fileName
              + ' '
              + linkName;
      ProcessUtils.ExitStatus res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      FileObject linkFO = getFileObject(baseDir + '/' + linkName);
      FileObject fileFO = getFileObject(baseDir + '/' + fileName);
      assertEquals(
          "Link and it's target modification time should be the same (as with java.io.File)",
          linkFO.lastModified(),
          fileFO.lastModified());
    } finally {
      removeRemoteDirIfNotNull(baseDir);
    }
  }
 @Override
 protected void buildProject(MakeProject makeProject, String command, long timeout, TimeUnit unit)
     throws Exception {
   try {
     super.buildProject(makeProject, command, timeout, unit);
   } catch (AssertionFailedError ex) {
     String localProjectDir = makeProject.getProjectDirectory().getPath();
     String remoteProjectDir =
         RemotePathMap.getPathMap(getTestExecutionEnvironment())
             .getRemotePath(localProjectDir, false);
     String zipName = "__rfs_remote_project__.zip";
     String remoteZip = remoteProjectDir + "/" + zipName;
     String localZip = localProjectDir + "/" + zipName;
     ExitStatus res =
         ProcessUtils.executeInDir(
             remoteProjectDir, getTestExecutionEnvironment(), "zip", "-r", "-q", remoteZip, ".");
     if (res.isOK()) {
       int rc =
           CommonTasksSupport.downloadFile(
                   remoteZip, getTestExecutionEnvironment(), localZip, null)
               .get();
       if (rc == 0) {
         System.err.printf("Remote project content copied to %s\n", localZip);
       } else {
         System.err.printf("Error downloading remote project content\n");
       }
     } else {
       System.err.printf(
           "Can not download remote project: rc=%d err=%s\n", res.exitCode, res.error);
     }
     throw ex;
   }
 }
  @ForAllEnvironments
  public void testLinkToItself() throws Exception {
    String baseDir = null;
    try {
      baseDir = mkTempAndRefreshParent(true);
      String linkName = "link";
      String script = "cd " + baseDir + "; " + "ln -s " + linkName + ' ' + linkName;
      ProcessUtils.ExitStatus res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      FileObject linkFO;

      linkFO = getFileObject(baseDir + '/' + linkName);
      linkFO.canRead();
    } finally {
      removeRemoteDirIfNotNull(baseDir);
    }
  }
  @ForAllEnvironments
  public void testCyclicLinksRefresh() throws Exception {
    String baseDir = null;
    try {
      baseDir = mkTempAndRefreshParent(true);
      String selfLinkName = "link";
      String linkName1 = "link1";
      String linkName2 = "link2";
      String baseDirlinkName = "linkToDir";
      String script =
          "cd "
              + baseDir
              + "; "
              + "ln -s "
              + selfLinkName
              + ' '
              + selfLinkName
              + ";"
              + "ln -s "
              + linkName1
              + ' '
              + linkName2
              + ";"
              + "ln -s "
              + linkName2
              + ' '
              + linkName1
              + ";"
              + "ln -s "
              + baseDir
              + ' '
              + baseDirlinkName;
      ProcessUtils.ExitStatus res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      FileObject baseDirFO = getFileObject(baseDir);
      baseDirFO.refresh();
      FileObject[] children =
          baseDirFO.getChildren(); // otherwise existent children are empty => refresh won't cycle
      baseDirFO.refresh();
    } finally {
      removeRemoteDirIfNotNull(baseDir);
    }
  }
  @ForAllEnvironments
  public void testDirectoryLink() throws Exception {
    String baseDir = null;
    try {
      baseDir = mkTempAndRefreshParent(true);

      String realDir = baseDir + "/real_dir";
      String linkDirName = "link_dir";
      String linkDir = baseDir + '/' + linkDirName;
      String realFile = realDir + "/file";
      String linkFile = linkDir + "/file";

      String script =
          "cd "
              + baseDir
              + "; "
              + "mkdir -p "
              + realDir
              + "; "
              + "ln -s "
              + realDir
              + ' '
              + linkDirName
              + "; "
              + "echo 123 > "
              + realFile;

      ProcessUtils.ExitStatus res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      FileObject realFO, linkFO;

      realFO = getFileObject(realFile);
      linkFO = getFileObject(linkFile);

      assertTrue("FileObject should be writable: " + linkFO.getPath(), linkFO.canWrite());
      String content = "a quick brown fox...";
      writeFile(linkFO, content);
      WritingQueue.getInstance(execEnv).waitFinished(null);
      CharSequence readContent = readFile(realFO);
      assertEquals("File content differ", content.toString(), readContent.toString());

      FileObject linkDirFO = getFileObject(linkDir);
      FileObject[] children = linkDirFO.getChildren();
      for (FileObject child : children) {
        String childPath = child.getPath();
        String parentPath = linkDirFO.getPath();
        assertTrue(
            "Incorrect link child path: "
                + childPath
                + " should start with parent path "
                + parentPath,
            child.getPath().startsWith(parentPath));
      }
      FileObject linkFO2;
      linkFO2 = getFileObject(linkFile);
      assertTrue("Duplicate instances for " + linkFile, linkFO == linkFO2);
      linkDirFO.refresh();
      linkFO2 = getFileObject(linkFile);
      assertTrue("Duplicate instances for " + linkFile, linkFO == linkFO2);
    } finally {
      removeRemoteDirIfNotNull(baseDir);
    }
  }
  @ForAllEnvironments
  public void testDirectoryLinkExternalUpdate() throws Exception {
    String baseDir = null;

    final String dataFile = "test";
    final String dirLink = "dir";
    final String content1 = "123";
    final String content2 = "321";

    try {
      baseDir = mkTempAndRefreshParent(true);
      String script =
          "cd "
              + baseDir
              + ";"
              + "mkdir -p "
              + baseDir
              + "/ade_autofs/111;"
              + "mkdir -p "
              + baseDir
              + "/ade_autofs/222;"
              + "echo "
              + content1
              + " > "
              + baseDir
              + "/ade_autofs/111/"
              + dataFile
              + ";"
              + "echo "
              + content2
              + " > "
              + baseDir
              + "/ade_autofs/222/"
              + dataFile
              + ";"
              + "ln -s "
              + baseDir
              + "/ade_autofs/111 "
              + baseDir
              + "/"
              + dirLink
              + ';';
      ProcessUtils.ExitStatus res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      FileObject baseDirFO = getFileObject(baseDir);
      FileObject dirLinkFO = getFileObject(baseDirFO, dirLink);
      FileObject dataFileFO = getFileObject(dirLinkFO, dataFile);

      assertTrue("FileObject should be readable: " + dataFileFO.getPath(), dataFileFO.canRead());
      CharSequence readContent = readFile(dataFileFO);
      assertEquals("File content differ", content1, readContent.toString());

      script =
          "cd "
              + baseDir
              + ";"
              + "rm "
              + baseDir
              + "/"
              + dirLink
              + ';'
              + "ln -s "
              + baseDir
              + "/ade_autofs/222 "
              + baseDir
              + "/"
              + dirLink
              + ';';
      res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      refreshFor(dataFileFO.getPath());
      assertTrue("FileObject should be readable: " + dataFileFO.getPath(), dataFileFO.canRead());
      readContent = readFile(dataFileFO);
      assertEquals("File content differ", content2, readContent.toString());

    } finally {
      removeRemoteDirIfNotNull(baseDir);
    }
  }
  @ForAllEnvironments
  public void testADELinkWorkflow() throws Exception {
    String baseDir = null;

    final String dataFile = "test";

    try {
      baseDir = mkTempAndRefreshParent(true);
      // The following directory structure emulates ADE real one.
      String script =
          "cd "
              + baseDir
              + ";"
              + "mkdir -p "
              + baseDir
              + "/ade_autofs/111/222;"
              + "echo 123 > "
              + baseDir
              + "/ade_autofs/111/222/"
              + dataFile
              + ";"
              + "chmod a-wx "
              + baseDir
              + "/ade_autofs/111/222/"
              + dataFile
              + ";"
              + "chmod a+r "
              + baseDir
              + "/ade_autofs/111/222/"
              + dataFile
              + ";"
              + "mkdir "
              + baseDir
              + "/ade;"
              + "ln -s "
              + baseDir
              + "/ade_autofs/111 "
              + baseDir
              + "/ade/111;"
              + "ln -s "
              + baseDir
              + "/ade/111/222 "
              + baseDir
              + "/ade_path;"
              + "ln -s ade_path/"
              + dataFile
              + ' '
              + dataFile;
      ProcessUtils.ExitStatus res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      FileObject baseDirFO = getFileObject(baseDir);
      FileObject dataFileFO = getFileObject(baseDirFO, dataFile);
      int hashCode = dataFileFO.hashCode();
      assertFalse(
          "FileObject should not be writable: " + dataFileFO.getPath(), dataFileFO.canWrite());

      script =
          "cd "
              + baseDir
              + "; "
              + "mv "
              + baseDir
              + "/ade_autofs/111/222/"
              + dataFile
              + ' '
              + dataFile
              + "; "
              + "chmod a+w "
              + dataFile;
      res = ProcessUtils.execute(execEnv, "sh", "-c", script);
      assertEquals("Error executing script \"" + script + "\": " + res.error, 0, res.exitCode);

      refreshFor(dataFileFO.getPath());
      assertEquals("FileObject hashCode should not change", hashCode, dataFileFO.hashCode());
      assertTrue("FileObject should be writable: " + dataFileFO.getPath(), dataFileFO.canWrite());
      String content = "another brown fox...";
      writeFile(dataFileFO, content);
      WritingQueue.getInstance(execEnv).waitFinished(null);
      CharSequence readContent = readFile(dataFileFO);
      assertEquals("File content differ", content.toString(), readContent.toString());

    } finally {
      removeRemoteDirIfNotNull(baseDir);
    }
  }