Package com.aragost.javahg.internals

Source Code of com.aragost.javahg.internals.ServerTest

/*
* #%L
* JavaHg
* %%
* Copyright (C) 2011 aragost Trifork ag
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
package com.aragost.javahg.internals;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;

import com.aragost.javahg.BaseRepository;
import com.aragost.javahg.Bundle;
import com.aragost.javahg.Changeset;
import com.aragost.javahg.Repository;
import com.aragost.javahg.RepositoryConfiguration;
import com.aragost.javahg.commands.AddCommand;
import com.aragost.javahg.commands.CommitCommand;
import com.aragost.javahg.commands.ExecutionException;
import com.aragost.javahg.commands.IncomingCommand;
import com.aragost.javahg.commands.LogCommand;
import com.aragost.javahg.commands.VersionCommand;
import com.aragost.javahg.test.AbstractTestCase;
import com.aragost.javahg.test.JavaHgTestExtension;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.io.Files;

public class ServerTest extends AbstractTestCase {

    private List<String> empty = Collections.emptyList();

    @Test
    public void testStartStop() throws IOException {
        File dir = Files.createTempDir();
        Server server = new Server(RepositoryConfiguration.DEFAULT.getHgBin(),
                                   RepositoryConfiguration.DEFAULT.getEncoding());
        server.initMecurialRepository(dir);
        server.start(dir, null, empty, null, null);
        server.stop();
        deleteTempDir(dir);
    }

    @Test
    public void testStopWhileProducingOutput() throws IOException {
        Repository repo = getTestRepository();
        Server server = getFirstServer(repo);
        InputStream stdout = server.runCommand(Lists.newArrayList("version"), VersionCommand.on(repo));

        // Nothing is yet read from stdout, stop the server. You
        // should then get
        // an IOException reading from stdout.
        server.stop();
        try {
            stdout.read();
            Assert.fail("IOException expected");
        } catch (IOException e) {
            // success
        }

        server.start(repo.getDirectory(), null, empty, null, null);

        VersionCommand.on(repo).execute();
    }

    @Test
    public void testLock() throws IOException, InterruptedException {
        Repository repo = getTestRepository();
        TestableCommand command = new TestableCommand(repo, "version");

        // The command must produce output so that it wont finish
        // before we empty the stdout. That way we can keep two
        // commands running at the same time and trigger the
        // IllegalStateException below .
        InputStream stdout = command.executeToStream();
        try {
            Server server = getFirstServer(repo);
            server.runCommand(Lists.newArrayList("version"), command);

            Assert.fail("Exception expected");
        } catch (IllegalStateException e) {
            Utils.consumeAll(stdout);
        }

        command.executeToStream();
    }

    @Test
    public void testServerRefCount() throws IOException {
        BaseRepository repo = getTestRepository();
        BaseRepository repo2 = getTestRepository2();
        writeFile("a");
        commit();
        Bundle bundle = IncomingCommand.on(repo2).execute(repo);
        Repository repo3 = bundle.getOverlayRepository();
        Assert.assertSame(repo2.getServerPool(), repo3.getServerPool());
        ServerPool pool = repo2.getServerPool();
        Assert.assertEquals(1, pool.getServers().size());
        Assert.assertNotNull(pool.getServers().get(0).getProcess());
        repo2.close();
        Assert.assertNotNull(pool.getServers().get(0).getProcess());
        Server server = pool.getServers().get(0);
        bundle.close();
        Assert.assertNull(server.getProcess());
        Assert.assertTrue(pool.getServers().isEmpty());
    }

    @Test
    public void testConfigChanges() throws IOException {
        BaseRepository repo = getTestRepository();
        GenericCommand cmd = new GenericCommand(repo, "version") {
            {
                {
                    cmdAppend("--config", "ui.username=xxx");
                }
            }
        };
        cmd.execute();
        writeFile("A");
        repo.workingCopy().add("A");
        try {
            // The previous config change is not forgotten
            CommitCommand commit = CommitCommand.on(repo).message("m");
            Changeset cs = commit.execute();
            assertFailedExecution(commit, "Username is " + cs.getUser());
        } catch (ExecutionException e) {
            Assert.assertTrue(e.getMessage().startsWith("no username supplied "));
        }
    }

    @Test
    public void testKillServerProcess() throws IOException {
        File dir = Files.createTempDir();
        RepositoryConfiguration repoConfig = new RepositoryConfiguration();
        repoConfig.addExtension(JavaHgTestExtension.class);
        Repository repo = Repository.create(repoConfig, dir);
        Process process = getFirstServer(repo).getProcess();
        process.destroy();
        // Process is dead and we can't send command
        try {
            VersionCommand cmd = VersionCommand.on(repo);
            cmd.execute();
            assertFailedExecution(cmd);
        } catch (UnexpectedServerTerminationException e) {
            // success
        }
        repo.close();

        repo = Repository.open(repoConfig, dir);
        String longStringThatDoesntFitInBuffers = Strings.repeat("x", 10 * 1000 * 1000);
        GenericCommand cmd = new GenericCommand(repo, "javahg-write");
        HgInputStream stream = cmd.launchStream("o", longStringThatDoesntFitInBuffers);
        boolean killed = killProcess(process);
        if (killed) {
            // Command is now sent, but we can't read output
            try {
                // String s =
                Utils.readStream(stream, repo.getServerPool().newDecoder());
                // TODO This doesn't work on Linux, why?
                // Assert.fail("Exception expected. Read " +
                // s.length() + " bytes");
            } catch (UnexpectedServerTerminationException e) {
                System.err.println("Exit value in testKillServerProcess: " + e.getExitValue());
                // success
            }
        }
        repo.close();

        deleteTempDir(dir);
    }

    @Test
    @Ignore
    public void testStderrDuringStartup() throws IOException {
        RepositoryConfiguration conf = new RepositoryConfiguration();
        String stderr = retrieveStartupStderr(conf);
        Assert.assertTrue("stderr=" + stderr,
                stderr.startsWith("*** failed to import extension javahgmissing from javahgmissing: [Errno 2]"));
    }

    @Test
    public void testStderrDuringStartupWillFullBuffer() throws IOException {
        RepositoryConfiguration conf = new RepositoryConfiguration();
        conf.setStderrBufferSize(1);
        String stderr = retrieveStartupStderr(conf);
        Assert.assertEquals("*", stderr);
    }

    /** validate that clone requiring auth will use auth in hgrc */
    @Test
    public void testCloneRequiringAuth() throws Exception {
        BaseRepository repoA = getTestRepository();

        writeFile(repoA, "x", "abc");
        AddCommand.on(repoA).execute();
        CommitCommand.on(repoA).message("added x").user("user").execute();

        // extension requires auth for requests via hg serve
        String extConfig = "extensions.ra="
                + Utils.resourceAsFile("/require-auth.py").getPath();

        // repository accessed via http requires auth

        ServeState serveState = startServing(repoA, "--config", extConfig);

        try {
            int port = serveState.getPort();

            // cloning with an hgrc with valid auth section should succeed
            File cloneDir = Files.createTempDir();
            Server server = new Server(
                    RepositoryConfiguration.DEFAULT.getHgBin(),
                    RepositoryConfiguration.DEFAULT.getEncoding());
            server.cloneMercurialRepository(cloneDir,
                    Utils.resourceAsFile("/test-hgrc-auth").getPath(),
                    "http://localhost:" + port);
            String xContents = Files.readFirstLine(new File(cloneDir, "x"),
                    utf8());
            Assert.assertEquals("abc", xContents);
            deleteTempDir(cloneDir);

            // cloning with no hgrc should generate auth exception
            File cloneDir2 = Files.createTempDir();
            Server server2 = new Server(
                    RepositoryConfiguration.DEFAULT.getHgBin(),
                    RepositoryConfiguration.DEFAULT.getEncoding());
            try {
                server2.cloneMercurialRepository(cloneDir, "",
                        "http://localhost:" + port);
                Assert.fail("Didn't get expected http authorization exception");
            } catch (Exception e) {
                if (!e.getMessage().contains("http authorization required")) {
                    Assert.fail("Didn't get expected http authorization exception. Got "
                            + e);
                }
            }
            deleteTempDir(cloneDir2);
        } finally {
            serveState.stop();
        }
    }

    /**
     * Helper function for a couple of test cases.
     *
     * @param conf
     * @return
     * @throws IOException
     */
    private String retrieveStartupStderr(RepositoryConfiguration conf) throws IOException {
        conf.setHgrcPath(Utils.resourceAsFile("/missing-extension.hgrc").getPath());
        File dir = Files.createTempDir();
        BaseRepository repo = Repository.create(conf, dir);
        String stderr = getFirstServer(repo).getStartupStderr();
        repo.close();
        deleteTempDir(dir);
        return stderr;
    }

    /**
     * Kill the process with 'kill -9'. The 'kill -9' does not give
     * the process a change to react to the kill signal. Using the
     * {@link Process#destroy()} the process is performing cleanup
     * <p>
     * This method calls the 'kill' via system call, and it will for
     * example not work on Windows. It is also using platform
     * dependent reflection code to obtain the pid of the process.
     *
     * @return true if 'kill' command was successful, false otherwise
     * @param process
     */
    private boolean killProcess(Process process) {
        int pid = readPid(process);
        if (pid != 0) {
            killProcess(pid);
            return true;
        }
        return false;
    }

    /**
     * Attempt to read the pid for the process. If not possible return
     * 0 otherwise return -1
     *
     * @param process
     * @return
     */
    private static int readPid(Process process) {
        try {
            Field pidField = process.getClass().getDeclaredField("pid");
            pidField.setAccessible(true);
            if (pidField.getType().equals(Integer.TYPE)) {
                String osName = System.getProperty("os.name");
                int pid = pidField.getInt(process);
                if (osName.startsWith("Mac OS X")) {
                    // Hmm, strange but it actuall seems like the
                    // value of
                    // the pid is 1 less than the actual pid?!
                    pid++;
                }
                return pid;
            }
        } catch (NoSuchFieldException e) {
            return 0;
        } catch (Exception e) {
            throw Utils.asRuntime(e);
        }
        return 0;
    }
   
    @Test
    public void testServerIdle() throws InterruptedException {
        RepositoryConfiguration conf = makeRepoConf();
        conf.setServerIdleTime(1);
        BaseRepository repo = Repository.create(conf, Files.createTempDir());

        Assert.assertEquals(1, repo.getServerPool().getNumIdleServers());

        Thread.sleep(2000);

        Assert.assertEquals(0, repo.getServerPool().getNumIdleServers());
        LogCommand.on(repo).execute();
        Assert.assertEquals(1, repo.getServerPool().getNumIdleServers());
    }
}
TOP

Related Classes of com.aragost.javahg.internals.ServerTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.