diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java index fefdc8b1..ff120322 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java @@ -31,7 +31,8 @@ import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ListBranchCommand; import org.eclipse.jgit.api.ListBranchCommand.ListMode; -import org.eclipse.jgit.api.PullCommand; +import org.eclipse.jgit.api.MergeCommand; +import org.eclipse.jgit.api.MergeResult; import org.eclipse.jgit.api.ResetCommand; import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.Status; @@ -40,10 +41,8 @@ import org.eclipse.jgit.api.TransportCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.transport.JschConfigSessionFactory; +import org.eclipse.jgit.transport.*; import org.eclipse.jgit.transport.OpenSshConfig.Host; -import org.eclipse.jgit.transport.SshSessionFactory; -import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.eclipse.jgit.util.FileUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.env.ConfigurableEnvironment; @@ -60,6 +59,7 @@ import com.jcraft.jsch.Session; * @author Roy Clarkson * @author Marcos Barbero * @author Daniel Lavoie + * @author Ryan Lynch */ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository implements EnvironmentRepository, SearchPathLocator, InitializingBean { @@ -141,11 +141,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository if (label == null) { label = this.defaultLabel; } - Ref ref = refresh(application, label); - String version = null; - if (ref != null) { - version = ref.getObjectId().getName(); - } + String version = refresh(label); return new Locations(application, profile, label, version, getSearchLocations(getWorkingDirectory(), application, profile, label)); } @@ -162,25 +158,31 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository /** * Get the working directory ready. */ - private Ref refresh(String application, String label) { + private String refresh(String label) { initialize(); Git git = null; try { git = createGitClient(); - git.getRepository().getConfig().setString("branch", label, "merge", label); - Ref ref = checkout(git, label); - if (shouldPull(git, ref)) { - pull(git, label, ref); - - if (!isClean(git)) { - logger.warn("The local repository is dirty. Reseting it to origin/" - + label + "."); - - fetch(git, label, "origin"); - resetHard(git, label, "refs/remotes/origin/" + label); + if (shouldPull(git)) { + fetch(git, label); + //checkout after fetch so we can get any new branches, tags, ect. + checkout(git, label); + if(isBranch(git, label)) { + //merge results from fetch + merge(git, label); + if (!isClean(git)) { + logger.warn("The local repository is dirty. Resetting it to origin/" + + label + "."); + resetHard(git, label, "refs/remotes/origin/" + label); + } } } - return ref; + else{ + //nothing to update so just checkout + checkout(git, label); + } + //always return what is currently HEAD as the version + return git.getRepository().getRef("HEAD").getObjectId().getName(); } catch (RefNotFoundException e) { throw new NoSuchLabelException("No such label: " + label); @@ -235,7 +237,8 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository return checkout.call(); } - /* for testing */ boolean shouldPull(Git git, Ref ref) throws GitAPIException { + + public /*public for testing*/ boolean shouldPull(Git git) throws GitAPIException { boolean shouldPull; Status gitStatus = git.status().call(); boolean isWorkingTreeClean = gitStatus.isClean(); @@ -247,7 +250,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository logDirty(gitStatus); } else { - shouldPull = isWorkingTreeClean && ref != null && originUrl != null; + shouldPull = isWorkingTreeClean && originUrl != null; } if (!isWorkingTreeClean && !this.forcePull) { this.logger.info("Cannot pull from remote " + originUrl @@ -277,56 +280,64 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository return isBranch(git, label) && !isLocalBranch(git, label); } - private void fetch(Git git, String label, String remote) { - FetchCommand fetch = git.fetch().setRemote(remote); + private FetchResult fetch(Git git, String label) { + FetchCommand fetch = git.fetch(); + fetch.setRemote("origin"); + fetch.setTagOpt(TagOpt.FETCH_TAGS); + setTimeout(fetch); try { if (hasText(getUsername())) { setCredentialsProvider(fetch); } - fetch.call(); + FetchResult result = fetch.call(); + if(result.getTrackingRefUpdates() != null && result.getTrackingRefUpdates().size() > 0) { + this.logger.info("Fetched for remote " + label + " and found " + result.getTrackingRefUpdates().size() + + " updates"); + } + return result; } catch (Exception ex) { this.logger.warn("Could not fetch remote for " + label + " remote: " + git .getRepository().getConfig().getString("remote", "origin", "url")); + return null; } } - private void resetHard(Git git, String label, String ref) { + private MergeResult merge(Git git, String label) { + try { + MergeCommand merge = git.merge(); + merge.include(git.getRepository().getRef("origin/" + label)); + MergeResult result = merge.call(); + if(!result.getMergeStatus().isSuccessful()) { + this.logger.warn("Merged from remote " + label + " with result " + result.getMergeStatus()); + } + return result; + } + catch (Exception ex) { + this.logger.warn("Could not merge remote for " + label + " remote: " + git + .getRepository().getConfig().getString("remote", "origin", "url")); + return null; + } + } + + private Ref resetHard(Git git, String label, String ref) { ResetCommand reset = git.reset(); reset.setRef(ref); reset.setMode(ResetType.HARD); try { - reset.call(); + Ref resetRef = reset.call(); + if(resetRef != null) { + this.logger.info("Reset label " + label + " to version " + resetRef.getObjectId()); + } + return resetRef; } catch (Exception ex) { this.logger.warn("Could not reset to remote for " + label + " (current ref=" + ref + "), remote: " + git.getRepository().getConfig() .getString("remote", "origin", "url")); - } - } - - /** - * Assumes we are on a tracking branch (should be safe) - */ - private void pull(Git git, String label, Ref ref) { - PullCommand pull = git.pull(); - setTimeout(pull); - try { - if (hasText(getUsername())) { - setCredentialsProvider(pull); - } - pull.call(); - } - catch (Exception e) { - this.logger - .warn("Could not pull remote for " + label + " (current ref=" + ref - + "), remote: " - + git.getRepository().getConfig().getString("remote", - "origin", "url") - + ", cause: (" + e.getClass().getSimpleName() + ") " - + e.getMessage()); + return null; } } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/test/ConfigServerTestUtils.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/test/ConfigServerTestUtils.java index 80b4d520..717bc5c7 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/test/ConfigServerTestUtils.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/test/ConfigServerTestUtils.java @@ -19,6 +19,8 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache.FileKey; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; +import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.config.environment.PropertySource; import org.springframework.util.FileSystemUtils; import org.springframework.util.StringUtils; @@ -111,4 +113,13 @@ public class ConfigServerTestUtils { return FileSystemUtils.deleteRecursively(dest); } + public static Object getProperty(Environment env, String sourceNameEndsWith, String property) { + for(PropertySource source: env.getPropertySources()) { + if(source.getName().endsWith(sourceNameEndsWith)) { + return source.getSource().get(property); + } + } + return null; + } + } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitConfigServerTestData.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitConfigServerTestData.java new file mode 100644 index 00000000..dc4c06fd --- /dev/null +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitConfigServerTestData.java @@ -0,0 +1,114 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * 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 org.springframework.cloud.config.server.environment; + + +import org.eclipse.jgit.api.Git; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.config.server.test.ConfigServerTestUtils; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.util.FileSystemUtils; +import org.springframework.util.ResourceUtils; + +import java.io.File; + +/** + * Class that holds objects that can be used for testing + * @author Ryan Lynch + */ +public class JGitConfigServerTestData { + + private LocalGit serverGit; + private LocalGit clonedGit; + private JGitEnvironmentRepository repository; + private ConfigurableApplicationContext context; + + public static class LocalGit { + private Git git; + private File gitWorkingDirectory; + + public LocalGit(Git git, File gitWorkingDirectory) { + this.git = git; + this.gitWorkingDirectory = gitWorkingDirectory; + } + + public Git getGit() { + return this.git; + } + + public File getGitWorkingDirectory() { + return this.gitWorkingDirectory; + } + } + + public JGitConfigServerTestData(LocalGit serverGit, LocalGit clonedGit, + JGitEnvironmentRepository repository, ConfigurableApplicationContext context) { + this.serverGit = serverGit; + this.clonedGit = clonedGit; + this.repository = repository; + this.context = context; + } + + public LocalGit getServerGit() { + return this.serverGit; + } + + public LocalGit getClonedGit() { + return this.clonedGit; + } + + public JGitEnvironmentRepository getRepository() { + return this.repository; + } + + public ConfigurableApplicationContext getContext() { + return this.context; + } + + public static JGitConfigServerTestData prepareClonedGitRepository(Object... sources) throws Exception { + //setup remote repository + String remoteUri = ConfigServerTestUtils.prepareLocalRepo(); + File remoteRepoDir = ResourceUtils.getFile(remoteUri); + Git remoteGit = Git.open(remoteRepoDir.getAbsoluteFile()); + remoteGit.checkout().setName("master").call(); + + //setup local repository + File clonedRepoDir = new File("target/repos/cloned"); + if(clonedRepoDir.exists()) { + FileSystemUtils.deleteRecursively(clonedRepoDir); + }else{ + clonedRepoDir.mkdirs(); + } + Git clonedGit = Git.cloneRepository() + .setURI( "file://" + remoteRepoDir.getAbsolutePath() ) + .setDirectory( clonedRepoDir ) + .setBranch("master") + .setCloneAllBranches(true) + .call(); + + //setup our test spring application pointing to the local repo + ConfigurableApplicationContext context = new SpringApplicationBuilder(sources).web(false) + .properties("spring.cloud.config.server.git.uri:" + "file://" + clonedRepoDir.getAbsolutePath()).run(); + JGitEnvironmentRepository repository = context.getBean(JGitEnvironmentRepository.class); + + return new JGitConfigServerTestData( + new JGitConfigServerTestData.LocalGit(remoteGit, remoteRepoDir), + new JGitConfigServerTestData.LocalGit(clonedGit, clonedRepoDir), + repository, context); + } + + +} diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryIntegrationTests.java index 1fc1247d..6f1fde9d 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryIntegrationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryIntegrationTests.java @@ -19,6 +19,7 @@ package org.springframework.cloud.config.server.environment; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -33,14 +34,16 @@ import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; +import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.util.FileUtils; import org.hamcrest.Matchers; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; @@ -60,6 +63,7 @@ import org.springframework.util.StreamUtils; * @author Dave Syer * @author Roy Clarkson * @author Daniel Lavoie + * @author Ryan Lynch */ public class JGitEnvironmentRepositoryIntegrationTests { @@ -155,7 +159,8 @@ public class JGitEnvironmentRepositoryIntegrationTests { .getBean(JGitEnvironmentRepository.class); // Fetches the repository for the first time. - repository.getLocations("bar", "test", "raw"); + SearchPathLocator.Locations locations = repository.getLocations("bar", "test", "raw"); + assertEquals(locations.getVersion(), commitToRevertBeforePull); // Resets to the original commit. git.reset().setMode(ResetType.HARD).setRef("master").call(); @@ -170,14 +175,17 @@ public class JGitEnvironmentRepositoryIntegrationTests { git.add().addFilepattern(".").call(); git.commit().setMessage("Conflicting commit.").call(); git.push().setForce(true).call(); + String conflictingCommit = git.log().setMaxCount(1).call().iterator() + .next().getName(); // Reset to the raw branch. git.reset().setMode(ResetType.HARD).setRef(commitToRevertBeforePull).call(); // Triggers the repository refresh. - repository.getLocations("bar", "test", "raw"); + locations = repository.getLocations("bar", "test", "raw"); + assertEquals(locations.getVersion(), conflictingCommit); - Assert.assertTrue("Local repository is not cleaned after retreiving resources.", + assertTrue("Local repository is not cleaned after retrieving resources.", git.status().call().isClean()); } @@ -326,6 +334,155 @@ public class JGitEnvironmentRepositoryIntegrationTests { repository.findOne("bar", "staging", "unknownlabel"); } + @Test + public void testVersionUpdate() throws Exception { + JGitConfigServerTestData testData = JGitConfigServerTestData.prepareClonedGitRepository(TestConfiguration.class); + + //get our starting versions + String startingLocalVersion = getCommitID(testData.getClonedGit().getGit(), "master"); + String startingRemoteVersion = getCommitID(testData.getServerGit().getGit(), "master"); + + //make sure we get the right version out of the gate + Environment environment = testData.getRepository().findOne("bar", "staging", "master"); + + //make sure the environments version is the same as the remote repo version + assertEquals(environment.getVersion(), startingRemoteVersion); + + //update the remote repo + FileOutputStream out = new FileOutputStream(new File(testData.getServerGit().getGitWorkingDirectory(), "bar.properties")); + StreamUtils.copy("foo: foo", Charset.defaultCharset(), out); + testData.getServerGit().getGit().add().addFilepattern("bar.properties").call(); + testData.getServerGit().getGit().commit().setMessage("Updated for pull").call(); + + //pull the environment again which should update the local repo from the just updated remote repo + environment = testData.getRepository().findOne("bar", "staging", "master"); + + //do some more check outs to get updated version numbers + String updatedLocalVersion = getCommitID(testData.getClonedGit().getGit(), "master"); + String updatedRemoteVersion = getCommitID(testData.getClonedGit().getGit(), "master"); + + //make sure our versions have been updated + assertEquals(updatedRemoteVersion, updatedLocalVersion); + assertNotEquals(updatedRemoteVersion, startingRemoteVersion); + assertNotEquals(updatedLocalVersion, startingLocalVersion); + + //make sure our environment also reflects the updated version + //this used to have a bug + assertEquals(environment.getVersion(), updatedRemoteVersion); + } + + @Test + public void testNewRemoteBranch() throws Exception { + JGitConfigServerTestData testData = JGitConfigServerTestData.prepareClonedGitRepository(TestConfiguration.class); + + Environment environment = testData.getRepository().findOne("bar", "staging", "master"); + Object fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "bar"); + + testData.getServerGit().getGit().branchCreate() + .setName("testNewRemoteBranch") + .call(); + + testData.getServerGit().getGit().checkout() + .setName("testNewRemoteBranch") + .call(); + + //update the remote repo + FileOutputStream out = new FileOutputStream( + new File(testData.getServerGit().getGitWorkingDirectory(), "/bar.properties")); + StreamUtils.copy("foo: branchBar", Charset.defaultCharset(), out); + testData.getServerGit().getGit().add().addFilepattern("bar.properties").call(); + testData.getServerGit().getGit().commit().setMessage("Updated for branch test").call(); + + environment = testData.getRepository().findOne("bar", "staging", "testNewRemoteBranch"); + fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "branchBar"); + } + + @Test + public void testNewRemoteTag() throws Exception { + JGitConfigServerTestData testData = JGitConfigServerTestData.prepareClonedGitRepository(TestConfiguration.class); + + Git serverGit = testData.getServerGit().getGit(); + + Environment environment = testData.getRepository().findOne("bar", "staging", "master"); + Object fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "bar"); + + serverGit.checkout().setName("master").call(); + + //create a new tag + serverGit.tag().setName("testTag").setMessage("Testing a tag").call(); + + //update the remote repo + FileOutputStream out = new FileOutputStream( + new File(testData.getServerGit().getGitWorkingDirectory(), "/bar.properties")); + StreamUtils.copy("foo: testAfterTag", Charset.defaultCharset(), out); + testData.getServerGit().getGit().add().addFilepattern("bar.properties").call(); + testData.getServerGit().getGit().commit().setMessage("Updated for branch test").call(); + + environment = testData.getRepository().findOne("bar", "staging", "master"); + fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "testAfterTag"); + + environment = testData.getRepository().findOne("bar", "staging", "testTag"); + fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "bar"); + + //now move the tag and test again + serverGit.tag().setName("testTag").setForceUpdate(true).setMessage("Testing a moved tag").call(); + + environment = testData.getRepository().findOne("bar", "staging", "testTag"); + fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "testAfterTag"); + + } + + @Test + public void testNewCommitID() throws Exception { + JGitConfigServerTestData testData = JGitConfigServerTestData.prepareClonedGitRepository(TestConfiguration.class); + + //get our starting versions + String startingRemoteVersion = getCommitID(testData.getServerGit().getGit(), "master"); + + //make sure we get the right version out of the gate + Environment environment = testData.getRepository().findOne("bar", "staging", "master"); + assertEquals(environment.getVersion(), startingRemoteVersion); + + //update the remote repo + FileOutputStream out = new FileOutputStream(new File(testData.getServerGit().getGitWorkingDirectory(), "bar.properties")); + StreamUtils.copy("foo: barNewCommit", Charset.defaultCharset(), out); + testData.getServerGit().getGit().add().addFilepattern("bar.properties").call(); + testData.getServerGit().getGit().commit().setMessage("Updated for pull").call(); + String updatedRemoteVersion = getCommitID(testData.getServerGit().getGit(), "master"); + + //do a normal request and verify we get the new version + environment = testData.getRepository().findOne("bar", "staging", "master"); + assertEquals(environment.getVersion(), updatedRemoteVersion); + Object fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "barNewCommit"); + + //request the prior commit ID and make sure we get it + environment = testData.getRepository().findOne("bar", "staging", startingRemoteVersion); + assertEquals(environment.getVersion(), startingRemoteVersion); + fooProperty = ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo"); + assertEquals(fooProperty, "bar"); + } + + + @Test(expected = NoSuchLabelException.class) + public void testUnknownLabelWithRemote() throws Exception { + JGitConfigServerTestData testData = JGitConfigServerTestData.prepareClonedGitRepository(TestConfiguration.class); + testData.getRepository().findOne("bar", "staging", "BADLabel"); + } + + private String getCommitID(Git git, String label) throws GitAPIException { + CheckoutCommand checkout = git.checkout(); + checkout.setName(label); + Ref localRef = checkout.call(); + return localRef.getObjectId().getName(); + } + @Configuration @EnableConfigurationProperties(ConfigServerProperties.class) @Import({ PropertyPlaceholderAutoConfiguration.class, diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java index 197439aa..3cd66c5e 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepositoryTests.java @@ -18,14 +18,27 @@ package org.springframework.cloud.config.server.environment; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.CloneCommand; +import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.ListBranchCommand; +import org.eclipse.jgit.api.MergeCommand; +import org.eclipse.jgit.api.ResetCommand; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.StatusCommand; +import org.eclipse.jgit.api.errors.InvalidRemoteException; +import org.eclipse.jgit.api.errors.NotMergedException; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.util.FileUtils; import org.junit.Before; import org.junit.Test; @@ -36,15 +49,11 @@ import org.springframework.core.env.StandardEnvironment; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; /** * @author Dave Syer @@ -139,8 +148,7 @@ public class JGitEnvironmentRepositoryTests { assertEquals(2, environment.getPropertySources().size()); assertEquals(this.repository.getUri() + "/bar.properties", environment .getPropertySources().get(0).getName()); - //TODO: why is the version null in tag? - assertNull("version was not null", environment.getVersion()); + assertVersion(environment); } @Test @@ -253,41 +261,16 @@ public class JGitEnvironmentRepositoryTests { this.environment); repo.setForcePull(true); - boolean shouldPull = repo.shouldPull(git, null); + boolean shouldPull = repo.shouldPull(git); assertThat("shouldPull was false", shouldPull, is(true)); } - @Test - public void shouldPullForcepullClean() throws Exception { - Git git = mock(Git.class); - StatusCommand statusCommand = mock(StatusCommand.class); - Status status = mock(Status.class); - Repository repository = mock(Repository.class); - StoredConfig storedConfig = mock(StoredConfig.class); - - when(git.status()).thenReturn(statusCommand); - when(git.getRepository()).thenReturn(repository); - when(repository.getConfig()).thenReturn(storedConfig); - when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); - when(statusCommand.call()).thenReturn(status); - when(status.isClean()).thenReturn(true); - - JGitEnvironmentRepository repo = new JGitEnvironmentRepository( - this.environment); - repo.setForcePull(true); - - boolean shouldPull = repo.shouldPull(git, null); - - assertThat("shouldPull was true", shouldPull, is(false)); - } - @Test public void shouldPullNotClean() throws Exception { Git git = mock(Git.class); StatusCommand statusCommand = mock(StatusCommand.class); Status status = mock(Status.class); - Ref ref = mock(Ref.class); Repository repository = mock(Repository.class); StoredConfig storedConfig = mock(StoredConfig.class); @@ -301,7 +284,7 @@ public class JGitEnvironmentRepositoryTests { JGitEnvironmentRepository repo = new JGitEnvironmentRepository( this.environment); - boolean shouldPull = repo.shouldPull(git, ref); + boolean shouldPull = repo.shouldPull(git); assertThat("shouldPull was true", shouldPull, is(false)); } @@ -311,7 +294,6 @@ public class JGitEnvironmentRepositoryTests { Git git = mock(Git.class); StatusCommand statusCommand = mock(StatusCommand.class); Status status = mock(Status.class); - Ref ref = mock(Ref.class); Repository repository = mock(Repository.class); StoredConfig storedConfig = mock(StoredConfig.class); @@ -325,11 +307,189 @@ public class JGitEnvironmentRepositoryTests { JGitEnvironmentRepository repo = new JGitEnvironmentRepository( this.environment); - boolean shouldPull = repo.shouldPull(git, ref); + boolean shouldPull = repo.shouldPull(git); assertThat("shouldPull was false", shouldPull, is(true)); } + @Test + public void testFetchException() throws Exception { + + Git git = mock(Git.class); + CloneCommand cloneCommand = mock(CloneCommand.class); + MockGitFactory factory = new MockGitFactory(git, cloneCommand); + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + this.repository.setGitFactory(factory); + + //refresh()->shouldPull + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + when(git.status()).thenReturn(statusCommand); + Repository repository = mock(Repository.class); + when(git.getRepository()).thenReturn(repository); + StoredConfig storedConfig = mock(StoredConfig.class); + when(repository.getConfig()).thenReturn(storedConfig); + when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true); + + //refresh()->fetch + FetchCommand fetchCommand = mock(FetchCommand.class); + when(git.fetch()).thenReturn(fetchCommand); + when(fetchCommand.setRemote(anyString())).thenReturn(fetchCommand); + when(fetchCommand.call()).thenThrow(new InvalidRemoteException("invalid mock remote")); //here is our exception we are testing + + //refresh()->checkout + CheckoutCommand checkoutCommand = mock(CheckoutCommand.class); + //refresh()->checkout->containsBranch + ListBranchCommand listBranchCommand = mock(ListBranchCommand.class); + when(git.checkout()).thenReturn(checkoutCommand); + when(git.branchList()).thenReturn(listBranchCommand); + List refs = new ArrayList<>(); + Ref ref = mock(Ref.class); + refs.add(ref); + when(ref.getName()).thenReturn("/master"); + when(listBranchCommand.call()).thenReturn(refs); + + //refresh()->merge + MergeCommand mergeCommand = mock(MergeCommand.class); + when(git.merge()).thenReturn(mergeCommand); + when(mergeCommand.call()).thenThrow(new NotMergedException()); //here is our exception we are testing + + //refresh()->return git.getRepository().getRef("HEAD").getObjectId().getName(); + Ref headRef = mock(Ref.class); + when(repository.getRef(anyString())).thenReturn(headRef); + + ObjectId newObjectId = ObjectId.fromRaw(new int[]{1,2,3,4,5}); + when(headRef.getObjectId()).thenReturn(newObjectId); + + SearchPathLocator.Locations locations = this.repository.getLocations("bar", "staging", null); + assertEquals(locations.getVersion(),newObjectId.getName()); + } + + + @Test + public void testMergeException() throws Exception { + + Git git = mock(Git.class); + CloneCommand cloneCommand = mock(CloneCommand.class); + MockGitFactory factory = new MockGitFactory(git, cloneCommand); + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + this.repository.setGitFactory(factory); + + //refresh()->shouldPull + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + when(git.status()).thenReturn(statusCommand); + Repository repository = mock(Repository.class); + when(git.getRepository()).thenReturn(repository); + StoredConfig storedConfig = mock(StoredConfig.class); + when(repository.getConfig()).thenReturn(storedConfig); + when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true); + + //refresh()->fetch + FetchCommand fetchCommand = mock(FetchCommand.class); + FetchResult fetchResult = mock(FetchResult.class); + when(git.fetch()).thenReturn(fetchCommand); + when(fetchCommand.setRemote(anyString())).thenReturn(fetchCommand); + when(fetchCommand.call()).thenReturn(fetchResult); + when(fetchResult.getTrackingRefUpdates()).thenReturn(Collections.EMPTY_LIST); + + //refresh()->checkout + CheckoutCommand checkoutCommand = mock(CheckoutCommand.class); + //refresh()->checkout->containsBranch + ListBranchCommand listBranchCommand = mock(ListBranchCommand.class); + when(git.checkout()).thenReturn(checkoutCommand); + when(git.branchList()).thenReturn(listBranchCommand); + List refs = new ArrayList<>(); + Ref ref = mock(Ref.class); + refs.add(ref); + when(ref.getName()).thenReturn("/master"); + when(listBranchCommand.call()).thenReturn(refs); + + //refresh()->merge + MergeCommand mergeCommand = mock(MergeCommand.class); + when(git.merge()).thenReturn(mergeCommand); + when(mergeCommand.call()).thenThrow(new NotMergedException()); //here is our exception we are testing + + //refresh()->return git.getRepository().getRef("HEAD").getObjectId().getName(); + Ref headRef = mock(Ref.class); + when(repository.getRef(anyString())).thenReturn(headRef); + + ObjectId newObjectId = ObjectId.fromRaw(new int[]{1,2,3,4,5}); + when(headRef.getObjectId()).thenReturn(newObjectId); + + SearchPathLocator.Locations locations = this.repository.getLocations("bar", "staging", "master"); + assertEquals(locations.getVersion(),newObjectId.getName()); + } + + @Test + public void testResetHardException() throws Exception { + + Git git = mock(Git.class); + CloneCommand cloneCommand = mock(CloneCommand.class); + MockGitFactory factory = new MockGitFactory(git, cloneCommand); + JGitEnvironmentRepository repo = new JGitEnvironmentRepository( + this.environment); + this.repository.setGitFactory(factory); + + //refresh()->shouldPull + StatusCommand statusCommand = mock(StatusCommand.class); + Status status = mock(Status.class); + when(git.status()).thenReturn(statusCommand); + Repository repository = mock(Repository.class); + when(git.getRepository()).thenReturn(repository); + StoredConfig storedConfig = mock(StoredConfig.class); + when(repository.getConfig()).thenReturn(storedConfig); + when(storedConfig.getString("remote", "origin", "url")).thenReturn("http://example/git"); + when(statusCommand.call()).thenReturn(status); + when(status.isClean()).thenReturn(true).thenReturn(false); + + //refresh()->fetch + FetchCommand fetchCommand = mock(FetchCommand.class); + FetchResult fetchResult = mock(FetchResult.class); + when(git.fetch()).thenReturn(fetchCommand); + when(fetchCommand.setRemote(anyString())).thenReturn(fetchCommand); + when(fetchCommand.call()).thenReturn(fetchResult); + when(fetchResult.getTrackingRefUpdates()).thenReturn(Collections.EMPTY_LIST); + + //refresh()->checkout + CheckoutCommand checkoutCommand = mock(CheckoutCommand.class); + //refresh()->checkout->containsBranch + ListBranchCommand listBranchCommand = mock(ListBranchCommand.class); + when(git.checkout()).thenReturn(checkoutCommand); + when(git.branchList()).thenReturn(listBranchCommand); + List refs = new ArrayList<>(); + Ref ref = mock(Ref.class); + refs.add(ref); + when(ref.getName()).thenReturn("/master"); + when(listBranchCommand.call()).thenReturn(refs); + + //refresh()->merge + MergeCommand mergeCommand = mock(MergeCommand.class); + when(git.merge()).thenReturn(mergeCommand); + when(mergeCommand.call()).thenThrow(new NotMergedException()); //here is our exception we are testing + + //refresh()->hardReset + ResetCommand resetCommand = mock(ResetCommand.class); + when(git.reset()).thenReturn(resetCommand); + when(resetCommand.call()).thenReturn(ref); + + //refresh()->return git.getRepository().getRef("HEAD").getObjectId().getName(); + Ref headRef = mock(Ref.class); + when(repository.getRef(anyString())).thenReturn(headRef); + + ObjectId newObjectId = ObjectId.fromRaw(new int[]{1,2,3,4,5}); + when(headRef.getObjectId()).thenReturn(newObjectId); + + SearchPathLocator.Locations locations = this.repository.getLocations("bar", "staging", "master"); + assertEquals(locations.getVersion(),newObjectId.getName()); + } + class MockGitFactory extends JGitEnvironmentRepository.JGitFactory { private Git mockGit; diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryTests.java index 9649881f..5a38a50c 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/MultipleJGitEnvironmentRepositoryTests.java @@ -109,7 +109,7 @@ public class MultipleJGitEnvironmentRepositoryTests { assertEquals(2, environment.getPropertySources().size()); assertEquals(this.repository.getUri() + "/bar.properties", environment .getPropertySources().get(0).getName()); - assertNull("version was not null", environment.getVersion()); + assertVersion(environment); } @Test