@VisibleForTesting
  static void moveIfDoesNotExist(Path source, Path destination) throws IOException {
    String errorMessage =
        String.format(
            "unable to move: %s to %s; such failures are often caused by interference from "
                + "antivirus (https://github.com/GoogleContainerTools/jib/issues/3127#issuecomment-796838294), "
                + "or rarely if the operation is not supported by the file system (for example: "
                + "special non-local file system)",
            source, destination);

    try {
      Action<IOException> rename =
          () -> {
            if (Files.exists(destination)) {
              // If the file already exists, we skip renaming and use the existing file.
              // This happens, e.g., if a new layer happens to have the same content as a
              // previously-cached layer or the same layer is being cached concurrently.
              return true;
            }
            Files.move(source, destination);
            return Files.exists(destination);
          };
      // Some Windows users report java.nio.file.AccessDeniedException that we suspect is caused
      // by anti-virus programs, like Windows Defender, that open new files for scanning.
      // Retry the rename up to 10 times, with 15ms pause between each retry.
      if (!Retry.action(rename)
          .maximumRetries(10)
          .retryOnException(ex -> ex instanceof FileSystemException)
          .sleep(15, TimeUnit.MILLISECONDS)
          .run()) {
        throw new IOException(errorMessage);
      }

    } catch (IOException ex) {
      throw new IOException(errorMessage, ex);
    }
  }
@Test
  public void testMoveIfDoesNotExist_exceptionAfterFailure() {
    Exception exception =
        assertThrows(
            IOException.class,
            () -> CacheStorageWriter.moveIfDoesNotExist(Paths.get("foo"), Paths.get("bar")));
    assertThat(exception)
        .hasMessageThat()
        .contains(
            "unable to move: foo to bar; such failures are often caused by interference from "
                + "antivirus");
    assertThat(exception).hasCauseThat().isInstanceOf(NoSuchFileException.class);
    assertThat(exception.getCause()).hasMessageThat().isEqualTo("foo");
  }