com.thoughtworks.go.domain.materials.svn.SvnCommandTest.java Source code

Java tutorial

Introduction

Here is the source code for com.thoughtworks.go.domain.materials.svn.SvnCommandTest.java

Source

/*
 * Copyright 2017 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.thoughtworks.go.domain.materials.svn;

import com.googlecode.junit.ext.JunitExtRunner;
import com.googlecode.junit.ext.RunIf;
import com.thoughtworks.go.config.materials.svn.SvnMaterial;
import com.thoughtworks.go.domain.materials.*;
import com.thoughtworks.go.helper.SvnTestRepo;
import com.thoughtworks.go.junitext.EnhancedOSChecker;
import com.thoughtworks.go.util.TestFileUtil;
import com.thoughtworks.go.util.command.*;
import org.apache.commons.io.FileUtils;
import org.hamcrest.Matchers;
import org.hamcrest.core.Is;
import org.jdom2.input.SAXBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import static com.thoughtworks.go.junitext.EnhancedOSChecker.DO_NOT_RUN_ON;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.WINDOWS;
import static com.thoughtworks.go.util.command.ProcessOutputStreamConsumer.inMemoryConsumer;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;

@RunWith(JunitExtRunner.class)
public class SvnCommandTest {
    public static SvnTestRepo testRepo;
    protected static final DotSvnIgnoringFilter DOT_SVN_IGNORING_FILTER = new DotSvnIgnoringFilter();

    protected String svnRepositoryUrl;
    protected File checkoutFolder;
    protected SvnCommand subversion;
    protected ProcessOutputStreamConsumer outputStreamConsumer;
    private final String svnInfoOutput = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
            + "   path=\"project1\"\n" + "   revision=\"27\">\n" + "<url>http://localhost/svn/project1</url>\n"
            + "<repository>\n" + "<root>http://localhost/svn/project1</root>\n"
            + "<uuid>b51fe673-20c0-4205-a07b-5deb54bb09f3</uuid>\n" + "</repository>\n" + "<commit\n"
            + "   revision=\"27\">\n" + "<author>anthill</author>\n" + "<date>2012-10-18T07:54:06.487895Z</date>\n"
            + "</commit>\n" + "</entry>\n" + "</info>";

    @Before
    public void setup() throws IOException {
        testRepo = new SvnTestRepo();
        svnRepositoryUrl = testRepo.projectRepositoryUrl();
        subversion = new SvnCommand(null, svnRepositoryUrl, "user", "pass", false);
        outputStreamConsumer = inMemoryConsumer();
        checkoutFolder = TestFileUtil.createUniqueTempFile("workingcopy" + System.currentTimeMillis());
    }

    @After
    public void teardown() {
        testRepo.tearDown();
        FileUtils.deleteQuietly(checkoutFolder);
    }

    @Test
    @RunIf(value = EnhancedOSChecker.class, arguments = { DO_NOT_RUN_ON, WINDOWS })
    public void shouldRecogniseSvnAsTheSameIfURLContainsSpaces() throws Exception {
        File working = TestFileUtil.createTempFolder("shouldRecogniseSvnAsTheSameIfURLContainsSpaces");
        SvnTestRepo repo = new SvnTestRepo("a directory with spaces");
        SvnMaterial material = repo.material();
        assertThat(material.getUrl(), containsString("%20"));
        InMemoryStreamConsumer output = new InMemoryStreamConsumer();
        material.freshCheckout(output, new SubversionRevision("3"), working);
        assertThat(output.getAllOutput(), containsString("Checked out revision 3"));

        InMemoryStreamConsumer output2 = new InMemoryStreamConsumer();
        material.updateTo(output2, working, new RevisionContext(new SubversionRevision("4")),
                new TestSubprocessExecutionContext());
        assertThat(output2.getAllOutput(), containsString("Updated to revision 4"));

    }

    @Test
    @RunIf(value = EnhancedOSChecker.class, arguments = { DO_NOT_RUN_ON, WINDOWS })
    public void shouldRecogniseSvnAsTheSameIfURLUsesFileProtocol() throws Exception {
        SvnTestRepo repo = new SvnTestRepo("svnRepo");
        File working = TestFileUtil.createTempFolder("someDir");
        SvnMaterial material = repo.material();
        InMemoryStreamConsumer output = new InMemoryStreamConsumer();
        material.freshCheckout(output, new SubversionRevision("3"), working);
        assertThat(output.getAllOutput(), containsString("Checked out revision 3"));

        InMemoryStreamConsumer output2 = new InMemoryStreamConsumer();
        updateMaterial(material, new SubversionRevision("4"), working, output2);
        assertThat(output2.getAllOutput(), containsString("Updated to revision 4"));

    }

    private void updateMaterial(SvnMaterial material, SubversionRevision revision, File working,
            InMemoryStreamConsumer output2) {
        material.updateTo(output2, working, new RevisionContext(revision), new TestSubprocessExecutionContext());
    }

    @Test
    @RunIf(value = EnhancedOSChecker.class, arguments = { DO_NOT_RUN_ON, WINDOWS })
    public void shouldRecogniseSvnAsTheSameIfURLContainsChineseCharacters() throws Exception {
        File working = TestFileUtil.createTempFolder("shouldRecogniseSvnAsTheSameIfURLContainsSpaces");
        SvnTestRepo repo = new SvnTestRepo("a directory with ?");
        SvnMaterial material = repo.material();
        assertThat(material.getUrl(), containsString("%20"));
        InMemoryStreamConsumer output = new InMemoryStreamConsumer();
        material.freshCheckout(output, new SubversionRevision("3"), working);
        assertThat(output.getAllOutput(), containsString("Checked out revision 3"));

        InMemoryStreamConsumer output2 = new InMemoryStreamConsumer();
        updateMaterial(material, new SubversionRevision("4"), working, output2);
        assertThat(output2.getAllOutput(), containsString("Updated to revision 4"));

    }

    @Test
    public void shouldFilterModifiedFilesByRepositoryURL() throws Exception {
        subversion = new SvnCommand(null, testRepo.end2endRepositoryUrl() + "/unit-reports", "user", "pass", false);
        List list = subversion.modificationsSince(new SubversionRevision(0));

        Modification modification = (Modification) list.get(0);
        assertThat(modification.getModifiedFiles().size(), is(3));
        for (ModifiedFile file : modification.getModifiedFiles()) {
            assertThat(file.getFileName().startsWith("/unit-reports"), is(true));
            assertThat(file.getFileName().startsWith("/ft-reports"), is(false));
        }
    }

    @Test
    public void shouldNotFilterModifiedFilesWhileURLPointsToRoot() throws Exception {
        subversion = new SvnCommand(null, testRepo.end2endRepositoryUrl(), "user", "pass", false);
        List list = subversion.modificationsSince(new SubversionRevision(0));

        Modification modification = (Modification) list.get(list.size() - 1);
        assertThat(modification.getModifiedFiles().size(), is(7));
    }

    @Test
    public void shouldCheckVCSConnection() throws Exception {
        ValidationBean validationBean = subversion.checkConnection();
        assertThat(validationBean.isValid(), is(true));
    }

    @Test
    public void shouldReplacePasswordWithStarWhenCheckSvnConnection() throws Exception {
        SvnCommand command = new SvnCommand(null, "http://do-not-care.com", "user", "password", false);
        ValidationBean validationBean = command.checkConnection();
        assertThat(validationBean.isValid(), is(false));
        assertThat(validationBean.getError(), containsString("INPUT"));
        assertThat(validationBean.getError(), containsString("******"));
    }

    @Test
    public void shouldGetModificationsFromSubversionSinceARevision() {
        final List list = subversion.modificationsSince(new SubversionRevision("1"));
        assertThat(list.size(), is(3));
        assertThat(((Modification) list.get(0)).getRevision(), is("4"));
        assertThat(((Modification) list.get(1)).getRevision(), is("3"));
        assertThat(((Modification) list.get(2)).getRevision(), is("2"));
    }

    @Test
    public void shouldGetLatestModificationFromSubversion() {
        final List<Modification> materialRevisions = subversion.latestModification();
        assertThat(materialRevisions.size(), is(1));
        final Modification modification = materialRevisions.get(0);
        assertThat(modification.getComment(), is("Added simple build shell to dump the environment to console."));
        assertThat(modification.getModifiedFiles().size(), is(1));
    }

    @Test
    public void shouldCheckoutToSpecificRevision() {
        subversion.checkoutTo(outputStreamConsumer, checkoutFolder, revision(2));
        assertThat(checkoutFolder.exists(), is(true));
        assertThat(checkoutFolder.listFiles().length, org.hamcrest.core.Is.is(not(0)));
        assertAtRevision(2, "TestReport-Unit.xml");
    }

    @Test
    public void shouldUpdateToSpecificRevision() {
        subversion.checkoutTo(outputStreamConsumer, checkoutFolder, SubversionRevision.HEAD);
        assertAtRevision(4, "TestReport-Unit.xml");
        subversion.updateTo(outputStreamConsumer, checkoutFolder, revision(2));
        assertAtRevision(2, "TestReport-Unit.xml");
        subversion.updateTo(outputStreamConsumer, checkoutFolder, revision(3));
        assertAtRevision(3, "revision3.txt");
    }

    @Test
    public void shouldThrowExceptionWithTheSecretHiddenWhenUpdateToFails() {
        subversion.checkoutTo(outputStreamConsumer, checkoutFolder, SubversionRevision.HEAD);
        assertAtRevision(4, "TestReport-Unit.xml");
        try {
            subversion.updateTo(outputStreamConsumer, checkoutFolder, revision(-1));
            fail("should throw exception");
        } catch (Exception e) {
            assertThat(e.getMessage(), containsString("--password ******"));
        }

    }

    @Test
    public void shouldUnlockAndRevertWorkingCopy() throws Exception {
        subversion.checkoutTo(outputStreamConsumer, checkoutFolder, SubversionRevision.HEAD);
        File file = checkoutFolder.listFiles(DOT_SVN_IGNORING_FILTER)[0];
        file.delete();
        assertThat(file.exists(), is(false));
        subversion.cleanupAndRevert(outputStreamConsumer, checkoutFolder);
        assertThat(file.exists(), is(true));
    }

    @Test
    public void shouldGetWorkingUrl() throws IOException {
        subversion.checkoutTo(outputStreamConsumer, checkoutFolder, SubversionRevision.HEAD);
        String url = subversion.workingRepositoryUrl(checkoutFolder);
        assertThat(URLDecoder.decode(url, "UTF-8"), is(svnRepositoryUrl));
    }

    protected void assertAtRevision(int rev, String file) {
        String[] filenames = checkoutFolder.list(DOT_SVN_IGNORING_FILTER);
        assertThat(filenames.length, Is.is(rev));
        assertThat(Arrays.asList(filenames), org.junit.matchers.JUnitMatchers.hasItem(file));
    }

    protected SubversionRevision revision(int revision) {
        return new SubversionRevision(revision);
    }

    public static class DotSvnIgnoringFilter implements FilenameFilter {
        public boolean accept(File dir, String name) {
            return !name.equals(".svn");
        }
    }

    @Test
    public void shouldParseSvnInfoWithParthDifferentFromUrl() throws Exception {
        String output = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
                + "   path=\"PurchaseDeliverables\"\n" + "   revision=\"36788\">\n"
                + "<url>http://svn.somewhere.com/someotherline/bloresvn/TISSIP/branch/DEV/PurchaseDeliverables</url>\n"
                + "<repository>\n" + "<root>http://svn.somewhere.com/someotherline</root>\n"
                + "<uuid>f6689194-972b-e749-89bf-11ebdadc4dc5</uuid>\n" + "</repository>\n" + "<commit\n"
                + "   revision=\"26449\">\n" + "<author>nigelfer</author>\n"
                + "<date>2009-02-03T15:43:08.059944Z</date>\n" + "</commit>\n" + "</entry>\n" + "</info>";
        SvnCommand.SvnInfo svnInfo = new SvnCommand.SvnInfo();
        svnInfo.parse(output, new SAXBuilder());
        assertThat(svnInfo.getPath(), is("/bloresvn/TISSIP/branch/DEV/PurchaseDeliverables"));
        assertThat(svnInfo.getUrl(),
                is("http://svn.somewhere.com/someotherline/bloresvn/TISSIP/branch/DEV/PurchaseDeliverables"));
    }

    @Test
    public void shouldParseSvnInfo() throws Exception {
        String output = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
                + "   path=\"someotherline\"\n" + "   revision=\"36788\">\n"
                + "<url>http://svn.somewhere.com/svn/someotherline</url>\n" + "<repository>\n"
                + "<root>http://svn.somewhere.com/svn</root>\n"
                + "<uuid>f6689194-972b-e749-89bf-11ebdadc4dc5</uuid>\n" + "</repository>\n" + "<commit\n"
                + "   revision=\"36788\">\n" + "<author>csebasti</author>\n"
                + "<date>2009-05-30T17:47:27.435599Z</date>\n" + "</commit>\n" + "</entry>\n" + "</info>";
        SvnCommand.SvnInfo svnInfo = new SvnCommand.SvnInfo();
        svnInfo.parse(output, new SAXBuilder());
        assertThat(svnInfo.getPath(), is("/someotherline"));
        assertThat(svnInfo.getUrl(), is("http://svn.somewhere.com/svn/someotherline"));
        assertThat(svnInfo.getRoot(), is("http://svn.somewhere.com/svn"));
    }

    @Test
    public void shouldParseSvnInfoWithUTF8ChineseNameInUrl() throws Exception {
        String output = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "  kind=\"dir\"\n"
                + "  path=\"?\"\n" + "  revision=\"4\">\n"
                + "<url>file:///home/cceuser/bigfs/projects/cruise/common/test-resources/unit/data/svnrepo/end2end/%E5%8F%B8%E5%BE%92%E7%A9%BA%E5%9C%A8%E6%AD%A4</url>\n"
                + "<repository>\n"
                + "<root>file:///home/cceuser/bigfs/projects/cruise/common/test-resources/unit/data/svnrepo/end2end</root>\n"
                + "<uuid>f953918e-915c-4459-8d4c-83860cce9d9a</uuid>\n" + "</repository>\n" + "<commit\n"
                + "  revision=\"4\">\n" + "<author></author>\n" + "<date>2009-05-31T04:14:44.223393Z</date>\n"
                + "</commit>\n" + "</entry>\n" + "</info>";
        SvnCommand.SvnInfo svnInfo = new SvnCommand.SvnInfo();
        svnInfo.parse(output, new SAXBuilder());
        assertThat(svnInfo.getPath(), is("/?"));
        assertThat(svnInfo.getUrl(), is(
                "file:///home/cceuser/bigfs/projects/cruise/common/test-resources/unit/data/svnrepo/end2end/%E5%8F%B8%E5%BE%92%E7%A9%BA%E5%9C%A8%E6%AD%A4"));
    }

    @Test
    public void shouldParseEncodedUrl() {
        String output = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
                + "   path=\"trunk\"\n" + "   revision=\"8650\">\n"
                + "<url>https://217.45.214.17:8443/svn/Entropy%20System/Envoy%20Enterprise/trunk</url>\n"
                + "<repository>\n" + "<root>https://217.45.214.17:8443/svn</root>\n"
                + "<uuid>3ed677eb-f12f-3343-ac77-786e4d01a301</uuid>\n" + "</repository>\n" + "<commit\n"
                + "   revision=\"8650\">\n" + "<author>BuildServer</author>\n"
                + "<date>2009-04-03 15:52:16 +0800 (Fri, 03 Apr 2009)</date>\n" + "</commit>\n" + "</entry>\n"
                + "</info>";
        SvnCommand.SvnInfo svnInfo = new SvnCommand.SvnInfo();
        svnInfo.parse(output, new SAXBuilder());
        assertThat(svnInfo.getUrl(),
                is("https://217.45.214.17:8443/svn/Entropy%20System/Envoy%20Enterprise/trunk"));
        assertThat(svnInfo.getPath(), is("/Entropy System/Envoy Enterprise/trunk"));
    }

    @Test
    public void shouldParseEncodedUrlAndPath() {
        String output = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
                + "   path=\"unit-reports\"\n" + "   revision=\"3\">\n"
                + "<url>file:///C:/Documents%20and%20Settings/cceuser/Local%20Settings/Temp/testSvnRepo-1243722556125/end2end/unit-reports</url>\n"
                + "<repository>\n"
                + "<root>file:///C:/Documents%20and%20Settings/cceuser/Local%20Settings/Temp/testSvnRepo-1243722556125/end2end</root>\n"
                + "<uuid>f953918e-915c-4459-8d4c-83860cce9d9a</uuid>\n" + "</repository>\n" + "<commit\n"
                + "   revision=\"1\">\n" + "<author>cceuser</author>\n"
                + "<date>2008-03-20T04:00:43.976517Z</date>\n" + "</commit>\n" + "</entry>\n" + "</info>";
        SvnCommand.SvnInfo svnInfo = new SvnCommand.SvnInfo();
        svnInfo.parse(output, new SAXBuilder());
        assertThat(svnInfo.getUrl(), is(
                "file:///C:/Documents%20and%20Settings/cceuser/Local%20Settings/Temp/testSvnRepo-1243722556125/end2end/unit-reports"));
        assertThat(svnInfo.getPath(), is("/unit-reports"));
    }

    @Test
    public void shouldParsePartlyEncodedUrlAndPath() {
        String output = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
                + "   path=\"unit-reports\"\n" + "   revision=\"3\">\n"
                + "<url>svn+ssh://hostname/foo%20bar%20baz/end2end</url>\n" + "<repository>\n"
                + "<root>svn+ssh://hostname/foo%20bar%20baz</root>\n"
                + "<uuid>f953918e-915c-4459-8d4c-83860cce9d9a</uuid>\n" + "</repository>\n" + "<commit\n"
                + "   revision=\"1\">\n" + "<author>cceuser</author>\n"
                + "<date>2008-03-20T04:00:43.976517Z</date>\n" + "</commit>\n" + "</entry>\n" + "</info>";
        SvnCommand.SvnInfo svnInfo = new SvnCommand.SvnInfo();
        svnInfo.parse(output, new SAXBuilder());
        assertThat(svnInfo.getUrl(), is("svn+ssh://hostname/foo%20bar%20baz/end2end"));
        assertThat(svnInfo.getPath(), is("/end2end"));
    }

    @Test
    public void shouldHidePasswordInUrl() {
        SvnCommand command = new SvnCommand(null,
                "https://user:password@217.45.214.17:8443/svn/Entropy%20System/Envoy%20Enterprise/trunk");
        assertThat(command.getUrlForDisplay(),
                is("https://user:******@217.45.214.17:8443/svn/Entropy%20System/Envoy%20Enterprise/trunk"));
    }

    @Test
    public void shouldSupportUTF8CheckInMessageAndFilename() throws Exception {
        String message = "?";
        String filename = "?.scn";
        testRepo.checkInOneFile(filename, message);

        Modification modification = subversion.latestModification().get(0);
        assertThat(modification.getComment(), is(message));
        assertThat(modification.getModifiedFiles().get(0).getFileName(), containsString(filename));
    }

    @Test
    public void shouldNotAddEmptyPasswordWhenUsernameIsProvidedWithNoPassword() throws IOException {
        SvnCommand command = new SvnCommand(null, "url", "shilpaIsGreat", null, false);
        CommandArgument argument = new StringArgument("--password=");
        assertThat(command.buildSvnLogCommandForLatestOne().getArguments(), not(hasItem(argument)));
    }

    @Test
    public void shouldNotAddEmptyPasswordWhenUsernameIsProvidedWithPassword() throws IOException {
        SvnCommand command = new SvnCommand(null, "url", "shilpaIsGreat", "noSheIsNot", false);
        CommandArgument argument = new StringArgument("--password");
        CommandArgument passArg = new PasswordArgument("noSheIsNot");
        assertThat(command.buildSvnLogCommandForLatestOne().getArguments(), hasItems(argument, passArg));
    }

    @Test
    public void shouldAddNothingWhenNoUsernameIsNotProvided() throws IOException {
        SvnCommand commandWithNullUsername = new SvnCommand(null, "url", null, null, false);

        assertThat(commandWithNullUsername.buildSvnLogCommandForLatestOne().toString().contains("--password="),
                is(false));
        assertThat(commandWithNullUsername.buildSvnLogCommandForLatestOne().toString().contains("--username"),
                is(false));

        SvnCommand commandWithEmptyUsername = new SvnCommand(null, "url", " ", " ", false);

        assertThat(commandWithEmptyUsername.buildSvnLogCommandForLatestOne().toString().contains("--password="),
                is(false));
        assertThat(commandWithEmptyUsername.buildSvnLogCommandForLatestOne().toString().contains("--username"),
                is(false));
    }

    @Test
    public void shouldGetSvnInfoAndReturnMapOfUrlToUUID() {
        final String svnInfoOutput = "<?xml version=\"1.0\"?>\n" + "<info>\n" + "<entry\n" + "   kind=\"dir\"\n"
                + "   path=\"project1\"\n" + "   revision=\"27\">\n" + "<url>http://localhost/svn/project1</url>\n"
                + "<repository>\n" + "<root>http://localhost/svn/project1</root>\n"
                + "<uuid>b51fe673-20c0-4205-a07b-5deb54bb09f3</uuid>\n" + "</repository>\n" + "<commit\n"
                + "   revision=\"27\">\n" + "<author>anthill</author>\n"
                + "<date>2012-10-18T07:54:06.487895Z</date>\n" + "</commit>\n" + "</entry>\n" + "</info>";
        final SvnMaterial svnMaterial = mock(SvnMaterial.class);
        when(svnMaterial.getUrl()).thenReturn("http://localhost/svn/project1");
        when(svnMaterial.getUserName()).thenReturn("user");
        when(svnMaterial.getPassword()).thenReturn("password");
        final ConsoleResult consoleResult = mock(ConsoleResult.class);
        when(consoleResult.outputAsString()).thenReturn(svnInfoOutput);
        final HashSet<SvnMaterial> svnMaterials = new HashSet<>();
        svnMaterials.add(svnMaterial);
        final SvnCommand spy = spy(subversion);
        doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                final CommandLine commandLine = (CommandLine) invocation.getArguments()[0];
                assertThat(commandLine.toString(), containsString(
                        "svn info --xml --username user --password ****** http://localhost/svn/project1"));
                return consoleResult;
            }
        }).when(spy).executeCommand(any(CommandLine.class));
        final HashMap<String, String> urlToRemoteUUIDMap = spy.createUrlToRemoteUUIDMap(svnMaterials);
        assertThat(urlToRemoteUUIDMap.size(), is(1));
        assertThat(urlToRemoteUUIDMap.get("http://localhost/svn/project1"),
                is("b51fe673-20c0-4205-a07b-5deb54bb09f3"));
    }

    @Test
    public void shouldGetSvnInfoForMultipleMaterialsAndReturnMapOfUrlToUUID() {
        final SvnMaterial svnMaterial1 = mock(SvnMaterial.class);
        when(svnMaterial1.getUrl()).thenReturn("http://localhost/svn/project1");
        final SvnMaterial svnMaterial2 = mock(SvnMaterial.class);
        when(svnMaterial2.getUrl()).thenReturn("http://foo.bar");
        final HashSet<SvnMaterial> svnMaterials = new HashSet<>();
        svnMaterials.add(svnMaterial1);
        svnMaterials.add(svnMaterial2);
        final SvnCommand spy = spy(subversion);
        doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                final ConsoleResult consoleResult = mock(ConsoleResult.class);
                when(consoleResult.outputAsString()).thenReturn(svnInfoOutput);
                final CommandLine commandLine = (CommandLine) invocation.getArguments()[0];
                if (commandLine.toString().contains("http://localhost/svn/project1")) {
                    return consoleResult;
                } else {
                    throw new RuntimeException("Some thing crapped out");
                }
            }
        }).when(spy).executeCommand(any(CommandLine.class));

        HashMap<String, String> urlToRemoteUUIDMap = null;
        try {
            urlToRemoteUUIDMap = spy.createUrlToRemoteUUIDMap(svnMaterials);
        } catch (Exception e) {
            fail("Should not have failed although exception was thrown " + e);
        }

        assertThat(urlToRemoteUUIDMap.size(), is(1));
        assertThat(urlToRemoteUUIDMap.get("http://localhost/svn/project1"),
                is("b51fe673-20c0-4205-a07b-5deb54bb09f3"));
        verify(spy, times(2)).executeCommand(any(CommandLine.class));
    }

    @Test
    public void shouldUseCorrectCredentialsPerSvnMaterialWhenQueryingForInfo() throws Exception {
        final String svnMaterial1Url = "http://localhost/svn/project1";
        final String svnMaterial1User = "svnMaterial1_user";
        final String svnMaterial1Password = "svnMaterial1_password";
        final SvnMaterial svnMaterial1 = buildMockSvnMaterial(svnMaterial1Url, svnMaterial1User,
                svnMaterial1Password);
        String svnMaterial2Url = "http://localhost/svn/project2";
        SvnMaterial svnMaterial2 = buildMockSvnMaterial(svnMaterial2Url, null, null);
        HashSet<SvnMaterial> svnMaterials = new HashSet<>();
        svnMaterials.add(svnMaterial1);
        svnMaterials.add(svnMaterial2);

        SvnCommand spy = spy(subversion);
        doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                final ConsoleResult consoleResult = mock(ConsoleResult.class);
                when(consoleResult.outputAsString()).thenReturn(svnInfoOutput);
                verifyCommandLine((CommandLine) invocation.getArguments()[0]);
                return consoleResult;
            }

            private void verifyCommandLine(CommandLine commandLine) {
                String commandString = commandLine.toStringForDisplay();
                if (commandString.contains(svnMaterial1User)) {
                    List<CommandArgument> arguments = commandLine.getArguments();
                    for (CommandArgument argument : arguments) {
                        if (argument instanceof PasswordArgument) {
                            assertThat(argument.forCommandline(), is(svnMaterial1Password));
                        }
                    }
                } else {
                    assertThat(commandString, not(Matchers.containsString("--username")));
                    assertThat(commandString, not(Matchers.containsString("password")));
                }
            }
        }).when(spy).executeCommand(any(CommandLine.class));

        HashMap<String, String> result = spy.createUrlToRemoteUUIDMap(svnMaterials);

        verify(svnMaterial1).getUserName();
        verify(svnMaterial1).getPassword();
        verify(svnMaterial2).getUserName();
        verify(svnMaterial2).getPassword();
    }

    private SvnMaterial buildMockSvnMaterial(String url, String username, String password) {
        final SvnMaterial svnMaterial = mock(SvnMaterial.class);
        when(svnMaterial.getUrl()).thenReturn(url);
        when(svnMaterial.getUserName()).thenReturn(username);
        when(svnMaterial.getPassword()).thenReturn(password);
        return svnMaterial;
    }
}