svnserver.SvnTestServer.java Source code

Java tutorial

Introduction

Here is the source code for svnserver.SvnTestServer.java

Source

/**
 * 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;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmatesoft.sqljet.core.internal.SqlJetPagerJournalMode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
import svnserver.config.*;
import svnserver.context.LocalContext;
import svnserver.context.SharedContext;
import svnserver.ext.gitlfs.storage.LfsStorageFactory;
import svnserver.ext.gitlfs.storage.memory.LfsMemoryStorage;
import svnserver.repository.VcsAccess;
import svnserver.repository.VcsRepositoryMapping;
import svnserver.repository.git.GitRepository;
import svnserver.repository.git.push.GitPushEmbedded;
import svnserver.repository.locks.PersistentLockFactory;
import svnserver.repository.mapping.RepositoryListMapping;
import svnserver.server.SvnServer;
import svnserver.tester.SvnTester;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Test subversion server.
 *
 * @author Artem V. Navrotskiy <bozaro@users.noreply.github.com>
 */
public final class SvnTestServer implements SvnTester {
    @NotNull
    private static final Logger log = LoggerFactory.getLogger(SvnTestServer.class);
    @NotNull
    public static final String USER_NAME = "tester";
    @NotNull
    public static final String USER_NAME_NO_MAIL = "nomail";
    @NotNull
    public static final String REAL_NAME = "Test User";
    @NotNull
    public static final String EMAIL = "foo@bar.org";
    @NotNull
    public static final String PASSWORD = "passw0rd";
    @NotNull
    private static final String TEST_BRANCH_PREFIX = "test_";

    @NotNull
    private final String BIND_HOST = "127.0.0.2";
    @NotNull
    private final File tempDirectory;
    @NotNull
    private final Repository repository;
    @NotNull
    private final String testBranch;
    @NotNull
    private final String prefix;
    @NotNull
    private final SvnServer server;
    @NotNull
    private final List<SvnOperationFactory> svnFactories = new ArrayList<>();

    private final boolean safeBranch;

    private SvnTestServer(@NotNull Repository repository, @Nullable String branch, @NotNull String prefix,
            boolean safeBranch, @Nullable UserDBConfig userDBConfig, boolean anonymousRead) throws Exception {
        SVNFileUtil.setSleepForTimestamp(false);
        this.repository = repository;
        this.safeBranch = safeBranch;
        this.prefix = prefix;
        tempDirectory = TestHelper.createTempDir("git-as-svn");
        final String srcBranch = branch == null ? repository.getBranch() : branch;
        if (safeBranch) {
            cleanupBranches(repository);
            testBranch = TEST_BRANCH_PREFIX + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
            new Git(repository).branchCreate().setName(testBranch).setStartPoint(srcBranch).call();
        } else {
            testBranch = srcBranch;
        }

        final Config config = new Config(BIND_HOST, 0);
        config.setCompressionEnabled(false);
        config.setCacheConfig(new MemoryCacheConfig());
        config.setRepositoryMapping(new TestRepositoryConfig(repository, testBranch, prefix, anonymousRead));
        if (userDBConfig != null) {
            config.setUserDB(userDBConfig);
        } else {
            config.setUserDB(new LocalUserDBConfig(new LocalUserDBConfig.UserEntry[] {
                    new LocalUserDBConfig.UserEntry(USER_NAME, REAL_NAME, EMAIL, PASSWORD),
                    new LocalUserDBConfig.UserEntry(USER_NAME_NO_MAIL, REAL_NAME, null, PASSWORD), }));
        }
        config.getShared().add(context -> context.add(LfsStorageFactory.class, new LfsMemoryStorage.Factory()));
        server = new SvnServer(tempDirectory, config);
        server.start();
        log.info("Temporary server started (url: {}, path: {}, branch: {} as {})", getUrl(),
                repository.getDirectory(), srcBranch, testBranch);
        log.info("Temporary directory: {}", tempDirectory);
    }

    private void cleanupBranches(Repository repository) {
        final List<String> branches = new ArrayList<>();
        for (String ref : repository.getAllRefs().keySet()) {
            if (ref.startsWith(Constants.R_HEADS + TEST_BRANCH_PREFIX)) {
                branches.add(ref.substring(Constants.R_HEADS.length()));
            }
        }
        if (!branches.isEmpty()) {
            for (String branch : branches) {
                log.info("Cleanup branch: {}", branch);
                try {
                    new Git(repository).branchDelete().setBranchNames(branch).setForce(true).call();
                } catch (GitAPIException e) {
                    log.error("Cleanup branch: " + branch, e);
                }
            }
        }
    }

    @NotNull
    public static SvnTestServer createEmpty() throws Exception {
        final String branch = "master";
        return new SvnTestServer(TestHelper.emptyRepository(), branch, "", false, null, true);
    }

    @NotNull
    public static SvnTestServer createEmpty(@Nullable UserDBConfig userDBConfig, boolean anonymousRead)
            throws Exception {
        final String branch = "master";
        return new SvnTestServer(TestHelper.emptyRepository(), branch, "", false, userDBConfig, anonymousRead);
    }

    @NotNull
    public static SvnTestServer createMasterRepository() throws Exception {
        return new SvnTestServer(new FileRepository(TestHelper.findGitPath()), null, "/master", true, null, true);
    }

    @Override
    @NotNull
    public SVNURL getUrl() throws SVNException {
        return SVNURL.create("svn", null, BIND_HOST, server.getPort(), prefix, true);
    }

    @NotNull
    public Repository getRepository() {
        return repository;
    }

    @NotNull
    public File getTempDirectory() {
        return tempDirectory;
    }

    public void shutdown(int millis) throws IOException, InterruptedException {
        server.shutdown(millis);
    }

    @Override
    public void close() throws Exception {
        shutdown(0);
        if (safeBranch) {
            new Git(repository).branchDelete().setBranchNames(testBranch).setForce(true).call();
        }
        for (SvnOperationFactory factory : svnFactories) {
            factory.dispose();
        }
        svnFactories.clear();
        repository.close();
        TestHelper.deleteDirectory(tempDirectory);
    }

    @NotNull
    public SvnOperationFactory createOperationFactory() {
        return createOperationFactory(USER_NAME, PASSWORD);
    }

    @NotNull
    public SvnOperationFactory createOperationFactory(@NotNull String userName, @NotNull String password) {
        final SVNWCContext wcContext = new SVNWCContext(new DefaultSVNOptions(getTempDirectory(), true), null);
        wcContext.setSqliteTemporaryDbInMemory(true);
        wcContext.setSqliteJournalMode(SqlJetPagerJournalMode.MEMORY);

        final SvnOperationFactory factory = new SvnOperationFactory(wcContext);
        factory.setAuthenticationManager(BasicAuthenticationManager.newInstance(userName, password.toCharArray()));
        svnFactories.add(factory);
        return factory;
    }

    @NotNull
    public SVNRepository openSvnRepository() throws SVNException {
        return openSvnRepository(USER_NAME, PASSWORD);
    }

    @NotNull
    public SVNRepository openSvnRepository(@NotNull String userName, @NotNull String password) throws SVNException {
        final SVNRepository repo = SVNRepositoryFactory.create(getUrl());
        repo.setAuthenticationManager(BasicAuthenticationManager.newInstance(userName, password.toCharArray()));
        return repo;
    }

    public void startShutdown() throws IOException {
        server.startShutdown();
    }

    @NotNull
    public SharedContext getContext() {
        return server.getContext();
    }

    private static class TestRepositoryConfig implements RepositoryMappingConfig {
        @NotNull
        private final Repository repository;
        @NotNull
        private final String branch;
        @NotNull
        private final String prefix;
        private final boolean anonymousRead;

        public TestRepositoryConfig(@NotNull Repository repository, @NotNull String branch, @NotNull String prefix,
                boolean anonymousRead) {
            this.repository = repository;
            this.branch = branch;
            this.prefix = prefix;
            this.anonymousRead = anonymousRead;
        }

        @NotNull
        @Override
        public VcsRepositoryMapping create(@NotNull SharedContext context) throws IOException, SVNException {
            final LocalContext local = new LocalContext(context, "test");
            final AclConfig aclConfig = new AclConfig();
            aclConfig.setAnonymousRead(anonymousRead);
            local.add(VcsAccess.class, aclConfig.create(local));
            return RepositoryListMapping.create(prefix, new GitRepository(local, repository,
                    new GitPushEmbedded(local, "", "", ""), branch, true, new PersistentLockFactory(local)));
        }
    }
}