/**
* This file is part of git-as-svn. It is subject to the license terms
* in the LICENSE file found in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/gpl-2.0.html. No part of git-as-svn,
* including this file, may be copied, modified, propagated, or distributed
* except according to the terms contained in the LICENSE file.
*/
package svnserver.server;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.*;
import svnserver.StringHelper;
import svnserver.SvnTestServer;
import svnserver.TestHelper;
import java.io.File;
import java.util.*;
import static svnserver.SvnTestHelper.sendDeltaAndClose;
/**
* Simple checkout tests.
*
* @author Artem V. Navrotskiy <bozaro@users.noreply.github.com>
*/
public class SvnCheckoutTest {
@NotNull
private static final Logger log = LoggerFactory.getLogger(SvnCheckoutTest.class);
@Test
public void checkoutRootRevision() throws Exception {
try (SvnTestServer server = SvnTestServer.createEmpty()) {
final SvnOperationFactory factory = server.createOperationFactory();
final SvnCheckout checkout = factory.createCheckout();
checkout.setSource(SvnTarget.fromURL(server.getUrl()));
checkout.setSingleTarget(SvnTarget.fromFile(server.getTempDirectory()));
checkout.setRevision(SVNRevision.create(0));
checkout.run();
}
}
/**
* Workcopy mixed version update smoke test.
*
* @throws Exception
*/
@Test
public void randomUpdateRoot() throws Exception {
checkUpdate("");
}
/**
* Workcopy mixed version update smoke test.
*
* @throws Exception
*/
@Test
public void randomUpdateChild() throws Exception {
checkUpdate("/src");
}
private void checkUpdate(@NotNull String basePath) throws Exception {
try (SvnTestServer server = SvnTestServer.createMasterRepository()) {
final SvnOperationFactory factory = server.createOperationFactory();
factory.setAutoCloseContext(false);
factory.setAutoDisposeRepositoryPool(false);
final SVNRepository repo = server.openSvnRepository();
final List<Long> revisions = loadUpdateRevisions(repo, basePath);
Assert.assertTrue(revisions.size() > 2);
final SvnCheckout checkout = factory.createCheckout();
checkout.setSource(SvnTarget.fromURL(server.getUrl().appendPath(basePath, false)));
checkout.setSingleTarget(SvnTarget.fromFile(server.getTempDirectory()));
checkout.setRevision(SVNRevision.create(revisions.get(0)));
checkout.run();
factory.setEventHandler(new ISVNEventHandler() {
@Override
public void handleEvent(SVNEvent event, double progress) throws SVNException {
Assert.assertEquals(event.getExpectedAction(), event.getAction());
}
@Override
public void checkCancelled() throws SVNCancelException {
}
});
final Random rand = new Random(0);
for (long revision : revisions.subList(1, revisions.size())) {
final SvnLog svnLog = factory.createLog();
svnLog.setSingleTarget(SvnTarget.fromURL(server.getUrl()));
svnLog.setRevisionRanges(Collections.singletonList(SvnRevisionRange.create(SVNRevision.create(revision - 1), SVNRevision.create(revision))));
svnLog.setDiscoverChangedPaths(true);
final SVNLogEntry logEntry = svnLog.run();
log.info("Update to revision #{}: {}", revision, StringHelper.getFirstLine(logEntry.getMessage()));
final TreeMap<String, SVNLogEntryPath> paths = new TreeMap<>(logEntry.getChangedPaths());
final List<String> targets = new ArrayList<>();
final SvnUpdate update = factory.createUpdate();
String lastAdded = null;
for (Map.Entry<String, SVNLogEntryPath> entry : paths.entrySet()) {
String path = entry.getKey();
if ((lastAdded != null) && path.startsWith(lastAdded)) {
continue;
}
if (entry.getValue().getType() == 'A') {
lastAdded = path + "/";
}
if (entry.getValue().getType() == 'A' || rand.nextBoolean()) {
if (path.startsWith(basePath)) {
final String subPath = path.substring(basePath.length());
targets.add(subPath.startsWith("/") ? subPath.substring(1) : subPath);
}
}
}
if (!targets.isEmpty()) {
for (String target : targets) {
update.addTarget(SvnTarget.fromFile(new File(server.getTempDirectory(), target)));
}
update.setRevision(SVNRevision.create(revision));
update.setSleepForTimestamp(false);
update.setMakeParents(true);
update.run();
}
}
}
}
@NotNull
private List<Long> loadUpdateRevisions(@NotNull SVNRepository repo, @NotNull String path) throws SVNException {
final long maxRevision = repo.getLatestRevision();
final LinkedList<Long> revisions = new LinkedList<>();
repo.log(new String[]{path}, maxRevision, 0, false, false, logEntry -> revisions.addFirst(logEntry.getRevision()));
return new ArrayList<>(revisions);
}
/**
* <pre>
* svn checkout
* echo > test.txt
* svn commit -m "create test.txt"
* rev N
* echo foo > test.txt
* svn commit -m "modify test.txt"
* svn up rev N
* </pre>
*
* @throws Exception
*/
@Test
public void checkoutAndUpdate() throws Exception {
try (SvnTestServer server = SvnTestServer.createEmpty()) {
final SVNRepository repo = server.openSvnRepository();
final ISVNEditor editor = repo.getCommitEditor("Intital state", null, false, null);
editor.openRoot(-1);
editor.addDir("/src", null, -1);
editor.addDir("/src/main", null, -1);
editor.addFile("/src/main/source.txt", null, -1);
editor.changeFileProperty("/src/main/source.txt", SVNProperty.EOL_STYLE, SVNPropertyValue.create(SVNProperty.EOL_STYLE_NATIVE));
sendDeltaAndClose(editor, "/src/main/source.txt", null, "Source content");
editor.closeDir();
editor.addDir("/src/test", null, -1);
editor.addFile("/src/test/test.txt", null, -1);
editor.changeFileProperty("/src/test/test.txt", SVNProperty.EOL_STYLE, SVNPropertyValue.create(SVNProperty.EOL_STYLE_NATIVE));
sendDeltaAndClose(editor, "/src/test/test.txt", null, "Test content");
editor.closeDir();
editor.closeDir();
editor.closeDir();
editor.closeEdit();
// checkout
final SvnOperationFactory factory = server.createOperationFactory();
final SvnCheckout checkout = factory.createCheckout();
checkout.setSource(SvnTarget.fromURL(server.getUrl()));
checkout.setSingleTarget(SvnTarget.fromFile(server.getTempDirectory()));
checkout.setRevision(SVNRevision.HEAD);
checkout.run();
final File file = new File(server.getTempDirectory(), "src/main/someFile.txt");
final SVNClientManager client = SVNClientManager.newInstance(factory);
// create file
final SVNCommitInfo commit;
{
Assert.assertFalse(file.exists());
TestHelper.saveFile(file, "New content");
client.getWCClient().doAdd(file, false, false, false, SVNDepth.INFINITY, false, true);
client.getWCClient().doSetProperty(file, SVNProperty.EOL_STYLE, SVNPropertyValue.create(SVNProperty.EOL_STYLE_NATIVE), false, SVNDepth.INFINITY, null, null);
commit = client.getCommitClient().doCommit(new File[]{file}, false, "Commit new file", null, null, false, false, SVNDepth.INFINITY);
}
// modify file
{
Assert.assertTrue(file.exists());
TestHelper.saveFile(file, "Modified content");
client.getCommitClient().doCommit(new File[]{file}, false, "Modify up-to-date commit", null, null, false, false, SVNDepth.INFINITY);
}
// update to previous commit
client.getUpdateClient().doUpdate(server.getTempDirectory(), SVNRevision.create(commit.getNewRevision()), SVNDepth.INFINITY, false, false);
// check no tree conflist
ArrayList<String> changeLists = new ArrayList<>();
client.getStatusClient().doStatus(server.getTempDirectory(), SVNRevision.WORKING, SVNDepth.INFINITY, false, false, true, false, status -> {
Assert.assertNull(status.getTreeConflict(), status.getFile().toString());
Assert.assertNull(status.getConflictNewFile(), status.getFile().toString());
}, changeLists);
Assert.assertTrue(changeLists.isEmpty());
}
}
}