/* * 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.config.materials.tfs; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.googlecode.junit.ext.JunitExtRunner; import com.thoughtworks.go.config.PasswordEncrypter; import com.thoughtworks.go.config.materials.AbstractMaterial; import com.thoughtworks.go.config.materials.PasswordAwareMaterial; import com.thoughtworks.go.domain.materials.Modification; import com.thoughtworks.go.domain.materials.TestSubprocessExecutionContext; import com.thoughtworks.go.domain.materials.ValidationBean; import com.thoughtworks.go.domain.materials.mercurial.StringRevision; import com.thoughtworks.go.domain.materials.tfs.TfsCommand; import com.thoughtworks.go.security.GoCipher; import com.thoughtworks.go.util.DataStructureUtils; import com.thoughtworks.go.util.ReflectionUtil; import com.thoughtworks.go.util.TempFiles; import com.thoughtworks.go.util.command.UrlArgument; import org.bouncycastle.crypto.InvalidCipherTextException; import org.hamcrest.Matchers; import org.hamcrest.core.Is; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import static com.thoughtworks.go.util.DataStructureUtils.m; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(JunitExtRunner.class) public class TfsMaterialTest { private TempFiles tempFiles; private TfsMaterial tfsMaterialFirstCollectionFirstProject; private TfsMaterial tfsMaterialFirstCollectionSecondProject; private final String DOMAIN = "domain"; private final String USERNAME = "username"; private final String PASSWORD = "password"; private final String TFS_FIRST_COLLECTION_URL = "http://some.tfs.repo.local"; private final String TFS_FIRST_PROJECT = "$/first_project"; private final String TFS_SECOND_PROJECT = "$/second_project"; @Before public void setUp() { GoCipher goCipher = mock(GoCipher.class); tempFiles = new TempFiles(); tfsMaterialFirstCollectionFirstProject = new TfsMaterial(goCipher, new UrlArgument(TFS_FIRST_COLLECTION_URL), USERNAME, DOMAIN, PASSWORD, TFS_FIRST_PROJECT); tfsMaterialFirstCollectionSecondProject = new TfsMaterial(goCipher, new UrlArgument(TFS_FIRST_COLLECTION_URL), USERNAME, DOMAIN, PASSWORD, TFS_SECOND_PROJECT); } @After public void tearDown() { tempFiles.cleanUp(); } @Test public void shouldShowLatestModification() { File dir = tempFiles.createUniqueFolder("tfs-dir"); TestSubprocessExecutionContext execCtx = new TestSubprocessExecutionContext(); TfsMaterial spy = spy(tfsMaterialFirstCollectionSecondProject); TfsCommand tfsCommand = mock(TfsCommand.class); when(tfsCommand.latestModification(dir)).thenReturn(new ArrayList<>()); doReturn(tfsCommand).when(spy).tfs(execCtx); List<Modification> actual = spy.latestModification(dir, execCtx); assertThat(actual, is(new ArrayList<Modification>())); verify(tfsCommand).latestModification(dir); } @Test public void shouldLoadAllModificationsSinceAGivenRevision() { File dir = tempFiles.createUniqueFolder("tfs-dir"); TestSubprocessExecutionContext execCtx = new TestSubprocessExecutionContext(); TfsMaterial spy = spy(tfsMaterialFirstCollectionFirstProject); TfsCommand tfsCommand = mock(TfsCommand.class); when(tfsCommand.modificationsSince(dir, new StringRevision("5"))).thenReturn(new ArrayList<>()); doReturn(tfsCommand).when(spy).tfs(execCtx); List<Modification> actual = spy.modificationsSince(dir, new StringRevision("5"), execCtx); assertThat(actual, is(new ArrayList<Modification>())); verify(tfsCommand).modificationsSince(dir, new StringRevision("5")); } @Test public void shouldInjectAllRelevantAttributesInSqlCriteriaMap() { TfsMaterial tfsMaterial = new TfsMaterial(new GoCipher(), new UrlArgument("my-url"), "loser", DOMAIN, "foo_bar_baz", "/dev/null"); assertThat(tfsMaterial.getSqlCriteria(), Is.is(DataStructureUtils.m( AbstractMaterial.SQL_CRITERIA_TYPE, (Object) "TfsMaterial", "url", "my-url", "username", "loser", "projectPath", "/dev/null", "domain", DOMAIN))); } @Test public void shouldInjectAllRelevantAttributesInAttributeMap() { TfsMaterial tfsMaterial = new TfsMaterial(new GoCipher(), new UrlArgument("my-url"), "loser", DOMAIN, "foo_bar_baz", "/dev/null"); assertThat(tfsMaterial.getAttributesForXml(), is(m( AbstractMaterial.SQL_CRITERIA_TYPE, (Object) "TfsMaterial", "url", "my-url", "username", "loser", "projectPath", "/dev/null", "domain", DOMAIN))); } @Test public void shouldReturnUrlForCommandLine_asUrl_IfSet() { TfsMaterial tfsMaterial = new TfsMaterial(new GoCipher(), new UrlArgument("http://foo:bar@my-url.com"), "loser", DOMAIN, "foo_bar_baz", "/dev/null" ); assertThat(tfsMaterial.getUrl(), is("http://foo:bar@my-url.com")); tfsMaterial = new TfsMaterial(new GoCipher(), null, "loser", DOMAIN, "foo_bar_baz", "/dev/null"); assertThat(tfsMaterial.getUrl(), is(nullValue())); } @Test public void shouldReturnUrlForCommandLine_asLocation_IfSet() { TfsMaterial tfsMaterial = new TfsMaterial(new GoCipher(), new UrlArgument("http://foo:bar@my-url.com"), "loser", DOMAIN, "foo_bar_baz", "/dev/null" ); assertThat(tfsMaterial.getLocation(), is("http://foo:******@my-url.com")); tfsMaterial = new TfsMaterial(new GoCipher(), null, "loser", DOMAIN, "foo_bar_baz", "/dev/null"); assertThat(tfsMaterial.getLocation(), is(nullValue())); } @Test public void shouldEncryptTfsPasswordAndMarkPasswordAsNull() throws Exception { GoCipher mockGoCipher = mock(GoCipher.class); when(mockGoCipher.encrypt("password")).thenReturn("encrypted"); TfsMaterial tfsMaterial = new TfsMaterial(mockGoCipher, new UrlArgument("/foo"), "username", DOMAIN, "password", ""); tfsMaterial.ensureEncrypted(); assertThat(tfsMaterial.getPassword(), is(nullValue())); assertThat(tfsMaterial.getEncryptedPassword(), is("encrypted")); } @Test public void shouldDecryptTfsPassword() throws Exception { GoCipher mockGoCipher = mock(GoCipher.class); when(mockGoCipher.decrypt("encrypted")).thenReturn("password"); TfsMaterial tfsMaterial = new TfsMaterial(mockGoCipher, new UrlArgument("/foo"), "username", DOMAIN, null, ""); ReflectionUtil.setField(tfsMaterial, "encryptedPassword", "encrypted"); tfsMaterial.ensureEncrypted(); assertThat(tfsMaterial.getPassword(), is("password")); } @Test public void shouldNotDecryptPasswordIfPasswordIsNotNull() throws Exception { GoCipher mockGoCipher = mock(GoCipher.class); when(mockGoCipher.encrypt("password")).thenReturn("encrypted"); when(mockGoCipher.decrypt("encrypted")).thenReturn("password"); TfsMaterial material = new TfsMaterial(mockGoCipher, new UrlArgument("/foo"), "username", DOMAIN, "password", ""); material.ensureEncrypted(); when(mockGoCipher.encrypt("new_password")).thenReturn("new_encrypted"); material.setPassword("new_password"); when(mockGoCipher.decrypt("new_encrypted")).thenReturn("new_password"); assertThat(material.getPassword(), is("new_password")); } @Test public void shouldErrorOutIfDecryptionFails() throws InvalidCipherTextException { GoCipher mockGoCipher = mock(GoCipher.class); String fakeCipherText = "fake cipher text"; when(mockGoCipher.decrypt(fakeCipherText)).thenThrow(new InvalidCipherTextException("exception")); TfsMaterial material = new TfsMaterial(mockGoCipher, new UrlArgument("/foo"), "username", DOMAIN, "password", ""); ReflectionUtil.setField(material, "encryptedPassword", fakeCipherText); try { material.getPassword(); fail("Should have thrown up"); } catch (Exception e) { assertThat(e.getMessage(), is("Could not decrypt the password to get the real password")); } } @Test public void shouldErrorOutIfEncryptionFails() throws Exception { GoCipher mockGoCipher = mock(GoCipher.class); when(mockGoCipher.encrypt("password")).thenThrow(new InvalidCipherTextException("exception")); try { new TfsMaterial(mockGoCipher, new UrlArgument("/foo"), "username", DOMAIN, "password", ""); fail("Should have thrown up"); } catch (Exception e) { assertThat(e.getMessage(), is("Password encryption failed. Please verify your cipher key.")); } } @Test public void shouldBePasswordAware() { assertThat(PasswordAwareMaterial.class.isAssignableFrom(TfsMaterial.class), is(true)); } @Test public void shouldBePasswordEncrypter() { assertThat(PasswordEncrypter.class.isAssignableFrom(TfsMaterial.class), is(true)); } @Test public void shouldKnowItsType() { assertThat(tfsMaterialFirstCollectionFirstProject.getTypeForDisplay(), is("Tfs")); } @Test public void shouldCheckConnection() { TestSubprocessExecutionContext execCtx = new TestSubprocessExecutionContext(); TfsCommand tfsCommand = mock(TfsCommand.class); doNothing().when(tfsCommand).checkConnection(); TfsMaterial spy = spy(tfsMaterialFirstCollectionFirstProject); doReturn(tfsCommand).when(spy).tfs(execCtx); assertThat(spy.checkConnection(execCtx), Is.is(ValidationBean.valid())); verify(tfsCommand, times(1)).checkConnection(); } @Test public void shouldGetLongDescriptionForMaterial(){ TfsMaterial material = new TfsMaterial(new GoCipher(), new UrlArgument("http://url/"),"user", "domain", "password", "$project/path/" ); assertThat(material.getLongDescription(), is("URL: http://url/, Username: user, Domain: domain, ProjectPath: $project/path/")); } @Test public void shouldCopyOverPasswordWhenConvertingToConfig() throws Exception { TfsMaterial material = new TfsMaterial(new GoCipher(), new UrlArgument("http://url/"),"user", "domain", "password", "$project/path/" ); TfsMaterialConfig config = (TfsMaterialConfig) material.config(); assertThat(config.getPassword(), is("password")); assertThat(config.getEncryptedPassword(), is(Matchers.not(Matchers.nullValue()))); } @Test public void shouldGetAttributesWithSecureFields() { TfsMaterial material = new TfsMaterial(new GoCipher(), new UrlArgument("http://username:password@tfsrepo.com"), "username", "domain", "password", "$project/path/"); Map<String, Object> attributes = material.getAttributes(true); assertThat(attributes.get("type"), is("tfs")); Map<String, Object> configuration = (Map<String, Object>) attributes.get("tfs-configuration"); assertThat(configuration.get("url"), is("http://username:password@tfsrepo.com")); assertThat(configuration.get("domain"), is("domain")); assertThat(configuration.get("username"), is("username")); assertThat(configuration.get("password"), is("password")); assertThat(configuration.get("project-path"), is("$project/path/")); } @Test public void shouldGetAttributesWithoutSecureFields() { TfsMaterial material = new TfsMaterial(new GoCipher(), new UrlArgument("http://username:password@tfsrepo.com"), "username", "domain", "password", "$project/path/"); Map<String, Object> attributes = material.getAttributes(false); assertThat(attributes.get("type"), is("tfs")); Map<String, Object> configuration = (Map<String, Object>) attributes.get("tfs-configuration"); assertThat(configuration.get("url"), is("http://username:******@tfsrepo.com")); assertThat(configuration.get("domain"), is("domain")); assertThat(configuration.get("username"), is("username")); assertThat(configuration.get("password"), is(nullValue())); assertThat(configuration.get("project-path"), is("$project/path/")); } }