package org.tmatesoft.svn.test; import org.junit.Assert; import org.junit.Assume; import org.junit.Ignore; import org.junit.Test; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.db.SVNSqlJetDb; import org.tmatesoft.svn.core.internal.db.SVNSqlJetSelectFieldsStatement; import org.tmatesoft.svn.core.internal.db.SVNSqlJetStatement; import org.tmatesoft.svn.core.internal.wc.SVNExternal; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc17.SVNWCContext; import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb; import org.tmatesoft.svn.core.internal.wc17.db.SVNWCDb; import org.tmatesoft.svn.core.internal.wc17.db.SvnWcDbStatementUtil; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbSchema; import org.tmatesoft.svn.core.internal.wc17.db.statement.SVNWCDbStatements; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.core.wc2.*; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Map; public class CopyTest { @Test public void testMoveBasePegRevision() throws Exception { testCopyBasePegRevision(true, "testMoveBasePegRevision"); } @Test public void testCopyBasePegRevision() throws Exception { testCopyBasePegRevision(false, "testCopyBasePegRevision"); } @Test public void testCopyDoesntCorruptPristineTable() throws Exception { //a test for a problem: a sha1 checksum was written to PRISTINE table instead of md5 checksum in some cases Assume.assumeTrue(TestUtil.isNewWorkingCopyTest()); final TestOptions options = TestOptions.getInstance(); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + "." + "testCopyDoesntCorruptPristineTable", options); try { final SVNURL url = sandbox.createSvnRepository(); final CommitBuilder commitBuilder1 = new CommitBuilder(url); commitBuilder1.addFile("directory1/file", "original contents".getBytes()); commitBuilder1.commit(); final CommitBuilder commitBuilder2 = new CommitBuilder(url); commitBuilder2.addDirectoryByCopying("directory2", "directory1"); commitBuilder2.addFile("directory2/anotherFile", "remote contents".getBytes()); commitBuilder2.commit(); final CommitBuilder commitBuilder3 = new CommitBuilder(url); commitBuilder3.changeFile("directory1/file", "new contents".getBytes()); commitBuilder3.commit(); final SVNURL directory1Url = url.appendPath("directory1", false); final SVNURL directory2Url = url.appendPath("directory2", false); final WorkingCopy workingCopy = sandbox.checkoutNewWorkingCopy(directory1Url); final File workingCopyDirectory = workingCopy.getWorkingCopyDirectory(); final SvnMerge merge = svnOperationFactory.createMerge(); merge.setSource(SvnTarget.fromURL(directory2Url, SVNRevision.create(2)), false); merge.addRevisionRange(SvnRevisionRange.create(SVNRevision.create(1), SVNRevision.create(2))); merge.setSingleTarget(SvnTarget.fromFile(workingCopyDirectory)); merge.run(); assertWCDbContainsCorrectChecksumTypesInPristineTable(svnOperationFactory, workingCopyDirectory); } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } @Test public void testWorkingToRepositoryCopy() throws Exception { final TestOptions options = TestOptions.getInstance(); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + ".testWorkingToRepositoryCopy", options); try { final SVNURL url = sandbox.createSvnRepository(); final CommitBuilder commitBuilder1 = new CommitBuilder(url); commitBuilder1.addFile("directory/file"); commitBuilder1.commit(); final CommitBuilder commitBuilder2 = new CommitBuilder(url); commitBuilder2.delete("directory"); commitBuilder2.commit(); final SVNURL subUrl = url.appendPath("directory", false); final WorkingCopy workingCopy = sandbox.checkoutNewWorkingCopy(subUrl, 1); final File workingCopyDirectory = workingCopy.getWorkingCopyDirectory(); final File localFile = new File(workingCopyDirectory, "local"); TestUtil.writeFileContentsString(localFile, "contents"); workingCopy.add(localFile); final SvnRemoteCopy remoteCopy = svnOperationFactory.createRemoteCopy(); remoteCopy.addCopySource(SvnCopySource.create(SvnTarget.fromFile(workingCopyDirectory), SVNRevision.create(1))); remoteCopy.setSingleTarget(SvnTarget.fromURL(url.appendPath("another directory", false))); final SVNCommitInfo commitInfo = remoteCopy.run(); Assert.assertEquals(3, commitInfo.getNewRevision()); //check SVN log SVNRepository svnRepository = SVNRepositoryFactory.create(url); try { final Collection logEntries = svnRepository.log(new String[]{""}, null, 3, 3, true, true); Assert.assertEquals(1, logEntries.size()); final SVNLogEntry logEntry = (SVNLogEntry) logEntries.iterator().next(); final Map<String, SVNLogEntryPath> changedPaths = logEntry.getChangedPaths(); Assert.assertEquals(1, changedPaths.size()); final SVNLogEntryPath logEntryPath = changedPaths.get("/another directory"); Assert.assertNotNull(logEntryPath); Assert.assertEquals(SVNNodeKind.DIR, logEntryPath.getKind()); Assert.assertEquals('A', logEntryPath.getType()); } finally { svnRepository.closeSession(); } } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } @Test public void testRepositoryToWorkingCopyCorrectRepositoryPathSvnAccess() throws Exception { final TestOptions options = TestOptions.getInstance(); Assume.assumeTrue(TestUtil.areAllSvnserveOptionsSpecified(options)); Assume.assumeTrue(TestUtil.isNewWorkingCopyTest()); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + ".testRepositoryToWorkingCopyCorrectRepositoryPathSvnAccess", options); try { final SVNURL url = sandbox.createSvnRepositoryWithSvnAccess(); Assume.assumeTrue(url.getPath().length() == 0); final CommitBuilder commitBuilder = new CommitBuilder(url); commitBuilder.addFile("sourceFile"); commitBuilder.addFile("targetFile"); commitBuilder.commit(); final WorkingCopy workingCopy = sandbox.checkoutNewWorkingCopy(url); final SVNURL sourceFileUrl = url.appendPath("sourceFile", false); final File targetFile = workingCopy.getFile("targetFile"); workingCopy.delete(targetFile); final SvnCopy copy = svnOperationFactory.createCopy(); copy.addCopySource(SvnCopySource.create(SvnTarget.fromURL(sourceFileUrl), SVNRevision.HEAD)); copy.setSingleTarget(SvnTarget.fromFile(targetFile)); copy.run(); assertNoRepositoryPathStartsWithSlash(svnOperationFactory, workingCopy.getWorkingCopyDirectory()); } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } @Ignore("SVNKIT-284, currently fails") @Test public void testRemoteCopyURLAutoEncodeCorruptsFilename() throws Exception { final TestOptions options = TestOptions.getInstance(); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + ".testRemoteCopyURLAutoEncodeCorruptsFilename", options); try { final SVNURL url = sandbox.createSvnRepository(); final CommitBuilder commitBuilder = new CommitBuilder(url); commitBuilder.addDirectory("directory"); commitBuilder.addFile("file%20with%20space"); commitBuilder.commit(); final SvnRemoteCopy remoteCopy = svnOperationFactory.createRemoteCopy(); remoteCopy.addCopySource(SvnCopySource.create(SvnTarget.fromURL(url.appendPath("file%20with%20space", false)), SVNRevision.HEAD)); remoteCopy.setSingleTarget(SvnTarget.fromURL(url.appendPath("directory", false))); remoteCopy.setFailWhenDstExists(false); remoteCopy.run(); final int[] count = {0}; final SvnList list = svnOperationFactory.createList(); list.setSingleTarget(SvnTarget.fromURL(url.appendPath("directory", false))); list.setReceiver(new ISvnObjectReceiver<SVNDirEntry>() { public void receive(SvnTarget target, SVNDirEntry dirEntry) throws SVNException { count[0]++; if (dirEntry.getKind() == SVNNodeKind.FILE) { Assert.assertEquals("file%20with%20space", dirEntry.getName()); } } }); list.run(); Assert.assertEquals(2, count[0]); } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } @Test public void testImpossibilityToMoveFileUnderUnversionedDirectory() throws Exception { //SVNKIT-295 final TestOptions options = TestOptions.getInstance(); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + ".testImpossibilityToMoveFileUnderUnversionedDirectory", options); try { final SVNURL url = sandbox.createSvnRepository(); final CommitBuilder commitBuilder = new CommitBuilder(url); commitBuilder.addFile("file"); commitBuilder.commit(); final WorkingCopy workingCopy = sandbox.checkoutNewWorkingCopy(url); final File file = workingCopy.getFile("file"); final File unversionedDirectory = workingCopy.getFile("unversionedDirectory"); SVNFileUtil.ensureDirectoryExists(unversionedDirectory); final File targetFile = new File(unversionedDirectory, "file"); final SVNClientManager clientManager = SVNClientManager.newInstance(); try { final SVNCopyClient copyClient = clientManager.getCopyClient(); copyClient.doCopy(new SVNCopySource[]{new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.WORKING, file)}, targetFile, true, false, true); Assert.fail("An exception should be thrown"); } catch (SVNException e) { //expected e.printStackTrace(); Assert.assertEquals(TestUtil.isNewWorkingCopyTest() ? SVNErrorCode.WC_PATH_NOT_FOUND : SVNErrorCode.WC_NOT_WORKING_COPY, e.getErrorMessage().getErrorCode()); } finally { clientManager.dispose(); } } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } @Test public void testWCWithExternalsToRepos() throws Exception { //SVNKIT-324 final TestOptions options = TestOptions.getInstance(); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + ".testWCWithExternalsToRepos", options); try { final SVNURL url = sandbox.createSvnRepository(); final SVNURL targetUrl = url.appendPath("target", false); final SVNExternal external = new SVNExternal("external", targetUrl.toString(), SVNRevision.HEAD, SVNRevision.HEAD, false, false, true); final CommitBuilder commitBuilder = new CommitBuilder(url); commitBuilder.addFile("file"); commitBuilder.setDirectoryProperty("", SVNProperty.EXTERNALS, SVNPropertyValue.create(external.toString())); commitBuilder.commit(); final WorkingCopy workingCopy = sandbox.checkoutNewWorkingCopy(url); final File workingCopyDirectory = workingCopy.getWorkingCopyDirectory(); final SvnRemoteCopy remoteCopy = svnOperationFactory.createRemoteCopy(); remoteCopy.addCopySource(SvnCopySource.create(SvnTarget.fromFile(workingCopyDirectory), SVNRevision.WORKING)); remoteCopy.setSingleTarget(SvnTarget.fromURL(targetUrl)); final SVNCommitInfo commitInfo = remoteCopy.run(); Assert.assertEquals(2, commitInfo.getNewRevision()); } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } private void assertNoRepositoryPathStartsWithSlash(SvnOperationFactory svnOperationFactory, File workingCopyDirectory) throws SVNException { final SVNWCContext context = new SVNWCContext(ISVNWCDb.SVNWCDbOpenMode.ReadOnly, svnOperationFactory.getOptions(), false, false, svnOperationFactory.getEventHandler()); try { final SVNWCDb db = (SVNWCDb) context.getDb(); final SVNWCDb.DirParsedInfo dirParsedInfo = db.parseDir(workingCopyDirectory, SVNSqlJetDb.Mode.ReadOnly); final SVNSqlJetDb sdb = dirParsedInfo.wcDbDir.getWCRoot().getSDb(); final SelectRepositoryRelPath selectRepositoryRelPath = new SelectRepositoryRelPath(sdb); try { selectRepositoryRelPath.bindf("i", dirParsedInfo.wcDbDir.getWCRoot().getWcId()); int recordsCount = 0; while (selectRepositoryRelPath.next()) { recordsCount++; final String reposPath = selectRepositoryRelPath.getColumnString(SVNWCDbSchema.NODES__Fields.repos_path); Assert.assertFalse(reposPath.startsWith("/")); } Assert.assertEquals(4, recordsCount); //1 for root, 1 for sourceFile, 2 for targetFile } finally { selectRepositoryRelPath.reset(); } } finally { context.close(); } } private void testCopyBasePegRevision(boolean move, String testName) throws SVNException, IOException { final TestOptions options = TestOptions.getInstance(); final SvnOperationFactory svnOperationFactory = new SvnOperationFactory(); final Sandbox sandbox = Sandbox.createWithCleanup(getTestName() + "." + testName, options); try { final SVNURL url = sandbox.createSvnRepository(); final CommitBuilder commitBuilder = new CommitBuilder(url); commitBuilder.addFile("sourceFile", "original contents".getBytes()); commitBuilder.commit(); final WorkingCopy workingCopy = sandbox.checkoutNewWorkingCopy(url); final File workingCopyDirectory = workingCopy.getWorkingCopyDirectory(); final File sourceFile = new File(workingCopyDirectory, "sourceFile"); final File targetFile = new File(workingCopyDirectory, "targetFile"); final String expectedNewContents = move ? "new contents" : "original contents"; TestUtil.writeFileContentsString(sourceFile, "new contents"); final SvnCopy copy = svnOperationFactory.createCopy(); copy.addCopySource(SvnCopySource.create(SvnTarget.fromFile(sourceFile, SVNRevision.BASE), SVNRevision.UNDEFINED)); copy.setSingleTarget(SvnTarget.fromFile(targetFile)); copy.setMove(move); copy.run(); Assert.assertTrue(targetFile.isFile()); final String actualNewContents = TestUtil.readFileContentsString(targetFile); Assert.assertEquals(expectedNewContents, actualNewContents); final Map<File, SvnStatus> statuses = TestUtil.getStatuses(svnOperationFactory, workingCopyDirectory); Assert.assertEquals(move ? SVNStatusType.STATUS_DELETED : SVNStatusType.STATUS_MODIFIED, statuses.get(sourceFile).getNodeStatus()); Assert.assertEquals(SVNStatusType.STATUS_ADDED, statuses.get(targetFile).getNodeStatus()); Assert.assertEquals(url.appendPath(sourceFile.getName(), false), statuses.get(targetFile).getCopyFromUrl()); } finally { svnOperationFactory.dispose(); sandbox.dispose(); } } private void assertWCDbContainsCorrectChecksumTypesInPristineTable(SvnOperationFactory svnOperationFactory, File workingCopyDirectory) throws SVNException { final SVNWCDb db = new SVNWCDb(); db.open(ISVNWCDb.SVNWCDbOpenMode.ReadOnly, svnOperationFactory.getOptions(), false, true); try { final SVNWCDb.DirParsedInfo dirParsedInfo = db.parseDir(workingCopyDirectory, SVNSqlJetDb.Mode.ReadOnly); final SVNSqlJetStatement selectMd5Statement = dirParsedInfo.wcDbDir.getWCRoot().getSDb().getStatement(SVNWCDbStatements.SELECT_PRISTINE_MD5_CHECKSUM); try { while (selectMd5Statement.next()) { final SvnChecksum md5Checksum = SvnWcDbStatementUtil.getColumnChecksum(selectMd5Statement, SVNWCDbSchema.PRISTINE__Fields.md5_checksum); final SvnChecksum sha1Checksum = SvnWcDbStatementUtil.getColumnChecksum(selectMd5Statement, SVNWCDbSchema.PRISTINE__Fields.checksum); Assert.assertEquals(SvnChecksum.Kind.md5, md5Checksum.getKind()); Assert.assertEquals(SvnChecksum.Kind.sha1, sha1Checksum.getKind()); } } finally { selectMd5Statement.reset(); } } finally { db.close(); } } private String getTestName() { return "CopyTest"; } private static class SelectRepositoryRelPath extends SVNSqlJetSelectFieldsStatement<SVNWCDbSchema.NODES__Fields> { public SelectRepositoryRelPath(SVNSqlJetDb sDb) throws SVNException { super(sDb, SVNWCDbSchema.NODES); } @Override protected void defineFields() { fields.add(SVNWCDbSchema.NODES__Fields.repos_path); } } }