Files
SCM-Manager/scm-it/src/test/java/sonia/scm/it/DiffITCase.java
Florian Scholdei dd7b07aeaf Retry failing integration tests
This uses 'RetryingTest' from junit jupiter to retry integration tests
that are known to fail from time to time. We explicitly mark single
tests in contrast to set a global retry to be able to trace those,
whenever this is intended.
2025-02-03 16:28:30 +01:00

276 lines
13 KiB
Java

/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.it;
import org.apache.http.HttpStatus;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junitpioneer.jupiter.RetryingTest;
import sonia.scm.it.utils.RepositoryUtil;
import sonia.scm.it.utils.ScmRequests;
import sonia.scm.it.utils.TestData;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.client.api.RepositoryClient;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.file.Files.createDirectories;
import static org.assertj.core.api.Assertions.assertThat;
import static sonia.scm.it.utils.RestUtil.ADMIN_PASSWORD;
import static sonia.scm.it.utils.RestUtil.ADMIN_USERNAME;
class DiffITCase {
@TempDir public Path tempFolder;
private RepositoryClient svnRepositoryClient;
private RepositoryClient gitRepositoryClient;
private RepositoryClient hgRepositoryClient;
private ScmRequests.RepositoryResponse<ScmRequests.IndexResponse> svnRepositoryResponse;
private ScmRequests.RepositoryResponse<ScmRequests.IndexResponse> hgRepositoryResponse;
private ScmRequests.RepositoryResponse<ScmRequests.IndexResponse> gitRepositoryResponse;
@BeforeEach
void init() throws IOException {
TestData.createDefault();
String namespace = ADMIN_USERNAME;
String repo = TestData.getDefaultRepoName("svn");
svnRepositoryResponse =
ScmRequests.start()
.requestIndexResource(ADMIN_USERNAME, ADMIN_PASSWORD)
.requestRepository(namespace, repo)
.assertStatusCode(HttpStatus.SC_OK);
File svnFolder = createDirectories(tempFolder.resolve("svn")).toFile();
svnRepositoryClient = RepositoryUtil.createRepositoryClient("svn", svnFolder);
repo = TestData.getDefaultRepoName("git");
gitRepositoryResponse =
ScmRequests.start()
.requestIndexResource(ADMIN_USERNAME, ADMIN_PASSWORD)
.requestRepository(namespace, repo)
.assertStatusCode(HttpStatus.SC_OK);
File gitFolder = createDirectories(tempFolder.resolve("git")).toFile();
gitRepositoryClient = RepositoryUtil.createRepositoryClient("git", gitFolder);
repo = TestData.getDefaultRepoName("hg");
hgRepositoryResponse =
ScmRequests.start()
.requestIndexResource(ADMIN_USERNAME, ADMIN_PASSWORD)
.requestRepository(namespace, repo)
.assertStatusCode(HttpStatus.SC_OK);
File hgFolder = createDirectories(tempFolder.resolve("hg")).toFile();
hgRepositoryClient = RepositoryUtil.createRepositoryClient("hg", hgFolder);
}
@Test
void shouldFindDiffsInGitFormat() throws IOException {
String svnDiff = getDiff(RepositoryUtil.createAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a"), svnRepositoryResponse);
String gitDiff = getDiff(RepositoryUtil.createAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a"), gitRepositoryResponse);
String hgDiff = getDiff(RepositoryUtil.createAndCommitFile(hgRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a"), hgRepositoryResponse);
assertThat(Lists.newArrayList(svnDiff, gitDiff, hgDiff))
.allSatisfy(diff -> assertThat(diff)
.contains("diff --git "));
}
@Test
void svnAddFileDiffShouldBeConvertedToGitDiff() throws IOException {
String svnDiff = getDiff(RepositoryUtil.createAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a"), svnRepositoryResponse);
String gitDiff = getDiff(RepositoryUtil.createAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a"), gitRepositoryResponse);
String expected = getGitDiffWithoutIndexLine(gitDiff);
assertDiffsAreEqual(svnDiff, expected);
}
@RetryingTest(3)
void svnDeleteFileDiffShouldBeConvertedToGitDiff() throws IOException {
RepositoryUtil.createAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a");
RepositoryUtil.createAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a");
String svnDiff = getDiff(RepositoryUtil.removeAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, "a.txt"), svnRepositoryResponse);
String gitDiff = getDiff(RepositoryUtil.removeAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, "a.txt"), gitRepositoryResponse);
String expected = getGitDiffWithoutIndexLine(gitDiff);
assertDiffsAreEqual(svnDiff, expected);
}
@RetryingTest(3)
void svnUpdateFileDiffShouldBeConvertedToGitDiff() throws IOException {
RepositoryUtil.createAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a");
RepositoryUtil.createAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, "a.txt", "content of a");
String svnDiff = getDiff(RepositoryUtil.updateAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, "a.txt", "the updated content of a"), svnRepositoryResponse);
String gitDiff = getDiff(RepositoryUtil.updateAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, "a.txt", "the updated content of a"), gitRepositoryResponse);
String expected = getGitDiffWithoutIndexLine(gitDiff);
assertDiffsAreEqual(svnDiff, expected);
}
@RetryingTest(3)
void svnMultipleChangesDiffShouldBeConvertedToGitDiff() throws IOException {
String svnDiff = getDiff(applyMultipleChanges(svnRepositoryClient, "fileToBeDeleted.txt", "fileToBeUpdated.txt", "addedFile.txt"), svnRepositoryResponse);
String gitDiff = getDiff(applyMultipleChanges(gitRepositoryClient, "fileToBeDeleted.txt", "fileToBeUpdated.txt", "addedFile.txt"), gitRepositoryResponse);
String endOfDiffPart = "\\ No newline at end of file\n";
String[] gitDiffs = gitDiff.split(endOfDiffPart);
List<String> expected = Arrays.stream(gitDiffs)
.map(this::getGitDiffWithoutIndexLine)
.collect(Collectors.toList());
assertThat(svnDiff.split(endOfDiffPart))
.containsExactlyInAnyOrderElementsOf(expected);
}
@Test
void svnMultipleSubFolderChangesDiffShouldBeConvertedToGitDiff() throws IOException {
String svnDiff = getDiff(applyMultipleChanges(svnRepositoryClient, "a/b/fileToBeDeleted.txt", "a/c/fileToBeUpdated.txt", "a/d/addedFile.txt"), svnRepositoryResponse);
String gitDiff = getDiff(applyMultipleChanges(gitRepositoryClient, "a/b/fileToBeDeleted.txt", "a/c/fileToBeUpdated.txt", "a/d/addedFile.txt"), gitRepositoryResponse);
String endOfDiffPart = "\\ No newline at end of file\n";
String[] gitDiffs = gitDiff.split(endOfDiffPart);
List<String> expected = Arrays.stream(gitDiffs)
.map(this::getGitDiffWithoutIndexLine)
.collect(Collectors.toList());
assertThat(svnDiff.split(endOfDiffPart))
.containsExactlyInAnyOrderElementsOf(expected);
}
@RetryingTest(3)
void svnLargeChangesDiffShouldBeConvertedToGitDiff() throws IOException, URISyntaxException {
String fileName = "SvnDiffGenerator_forTest";
RepositoryUtil.createAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, fileName, "");
RepositoryUtil.createAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, fileName, "");
String fileContent = getFileContent("/diff/largefile/original/SvnDiffGenerator_forTest");
String svnDiff = getDiff(RepositoryUtil.updateAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, fileName, fileContent), svnRepositoryResponse);
String gitDiff = getDiff(RepositoryUtil.updateAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, fileName, fileContent), gitRepositoryResponse);
assertDiffsAreEqual(svnDiff, getGitDiffWithoutIndexLine(gitDiff));
fileContent = getFileContent("/diff/largefile/modified/v1/SvnDiffGenerator_forTest");
svnDiff = getDiff(RepositoryUtil.updateAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, fileName, fileContent), svnRepositoryResponse);
gitDiff = getDiff(RepositoryUtil.updateAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, fileName, fileContent), gitRepositoryResponse);
assertDiffsAreEqual(svnDiff, getGitDiffWithoutIndexLine(gitDiff));
fileContent = getFileContent("/diff/largefile/modified/v2/SvnDiffGenerator_forTest");
svnDiff = getDiff(RepositoryUtil.updateAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, fileName, fileContent), svnRepositoryResponse);
gitDiff = getDiff(RepositoryUtil.updateAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, fileName, fileContent), gitRepositoryResponse);
assertDiffsAreEqual(svnDiff, getGitDiffWithoutIndexLine(gitDiff));
}
/**
* FIXME: the binary Git Diff output is not GIT conform
*/
@Test
@Disabled
@SuppressWarnings("squid:S1607")
void svnBinaryChangesDiffShouldBeConvertedToGitDiff() throws IOException, URISyntaxException {
String fileName = "binary";
File file = new File(svnRepositoryClient.getWorkingCopy(), fileName);
Files.copy(Paths.get(getClass().getResource("/diff/binaryfile/echo").toURI()), Paths.get(file.toURI()));
Changeset commit = RepositoryUtil.addFileAndCommit(svnRepositoryClient, fileName, ADMIN_USERNAME, "");
file = new File(gitRepositoryClient.getWorkingCopy(), fileName);
Files.copy(Paths.get(getClass().getResource("/diff/binaryfile/echo").toURI()), Paths.get(file.toURI()));
Changeset commit1 = RepositoryUtil.addFileAndCommit(gitRepositoryClient, fileName, ADMIN_USERNAME, "");
String svnDiff = getDiff(commit, svnRepositoryResponse);
String gitDiff = getDiff(commit1, gitRepositoryResponse);
assertDiffsAreEqual(svnDiff, getGitDiffWithoutIndexLine(gitDiff));
}
@RetryingTest(3)
void svnRenameChangesDiffShouldBeConvertedToGitDiff() throws IOException, URISyntaxException {
String fileName = "a.txt";
RepositoryUtil.createAndCommitFile(svnRepositoryClient, ADMIN_USERNAME, fileName, "content of a");
RepositoryUtil.createAndCommitFile(gitRepositoryClient, ADMIN_USERNAME, fileName, "content of a");
String newFileName = "renamed_a.txt";
File file = new File(svnRepositoryClient.getWorkingCopy(), fileName);
file.renameTo(new File(svnRepositoryClient.getWorkingCopy(), newFileName));
String svnDiff = getDiff(RepositoryUtil.addFileAndCommit(svnRepositoryClient, newFileName, ADMIN_USERNAME, "renamed file"), svnRepositoryResponse);
file = new File(gitRepositoryClient.getWorkingCopy(), fileName);
file.renameTo(new File(gitRepositoryClient.getWorkingCopy(), newFileName));
String gitDiff = getDiff(RepositoryUtil.addFileAndCommit(gitRepositoryClient, newFileName, ADMIN_USERNAME, "renamed file"), gitRepositoryResponse);
String expected = getGitDiffWithoutIndexLine(gitDiff);
assertDiffsAreEqual(svnDiff, expected);
}
public String getFileContent(String name) throws URISyntaxException, IOException {
Path path;
path = Paths.get(getClass().getResource(name).toURI());
Stream<String> lines = Files.lines(path);
String data = lines.collect(Collectors.joining("\n"));
lines.close();
return data;
}
/**
* The index line is not provided from the svn git formatter and it is not needed in the ui diff view
* for more details about the git diff format: https://git-scm.com/docs/git-diff
*
* @param gitDiff
* @return diff without the index line
*/
private String getGitDiffWithoutIndexLine(String gitDiff) {
return gitDiff.replaceAll(".*(index.*\n)", "");
}
private void assertDiffsAreEqual(String svnDiff, String gitDiff) {
assertThat(svnDiff)
.as("diffs are different\n\nsvn:\n==================================================\n\n%s\n\ngit:\n==================================================\n\n%s)", svnDiff, gitDiff)
.isEqualTo(gitDiff);
}
private String getDiff(Changeset svnChangeset, ScmRequests.RepositoryResponse<ScmRequests.IndexResponse> svnRepositoryResponse) {
return svnRepositoryResponse.requestChangesets()
.requestDiffInGitFormat(svnChangeset.getId())
.getResponse()
.body()
.asString();
}
private Changeset applyMultipleChanges(RepositoryClient repositoryClient, String fileToBeDeleted, final String fileToBeUpdated, final String addedFile) throws IOException {
RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileToBeDeleted, "file to be deleted");
RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileToBeUpdated, "file to be updated");
Map<String, String> addedFiles = new HashMap<String, String>() {{
put(addedFile, "content");
}};
Map<String, String> modifiedFiles = new HashMap<String, String>() {{
put(fileToBeUpdated, "the updated content");
}};
ArrayList<String> removedFiles = Lists.newArrayList(fileToBeDeleted);
return RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles);
}
}