Merge remote-tracking branch 'origin/1.4.x' into 2.0.x

This commit is contained in:
Ryan Baxter
2018-11-19 16:27:21 -05:00
3 changed files with 151 additions and 3 deletions

View File

@@ -971,8 +971,11 @@ The asymmetric choice is superior in terms of security, but it is often more con
To configure a symmetric key, you need to set `encrypt.key` to a secret String (or use the `ENCRYPT_KEY` environment variable to keep it out of plain-text configuration files).
To configure an asymmetric key, you can either set the key as a PEM-encoded text value (in `encrypt.key`) or use a keystore (such as the keystore created by the `keytool` utility that comes with the JDK).
The following table describes the keystore properties:
NOTE: You cannot configure an asymmetric key using `encrypt.key`.
To configure an asymmetric key use a keystore (e.g. as
created by the `keytool` utility that comes with the JDK). The
keystore properties are `encrypt.keyStore.\*` with `*` equal to
[options="header"]
|===

View File

@@ -243,7 +243,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
}
@Override
public void afterPropertiesSet() throws Exception {
public synchronized void afterPropertiesSet() throws Exception {
Assert.state(getUri() != null,
MESSAGE);
initialize();

View File

@@ -17,12 +17,24 @@
package org.springframework.cloud.config.server.environment;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.errors.*;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.util.FileUtils;
import org.junit.After;
import org.junit.Before;
@@ -96,6 +108,63 @@ public class JGitEnvironmentRepositoryConcurrencyTests {
assertEquals("master", environment.getLabel());
}
protected Log logger = LogFactory.getLog(getClass());
/**
* Simulates following actions in parallel:
* - Client tries to obtain configuration with specified label
* - Spring Refresh Context Event occurs
*/
@Test
public void concurrentRefreshContextAndGetLabels() throws Exception {
// Prepare the repo
final JGitConfigServerTestData testData = JGitConfigServerTestData.prepareClonedGitRepository(TestConfiguration.class);
JGitEnvironmentRepository repository = testData.getRepository();
repository.setCloneOnStart(true);
repository.setGitFactory(new DelayedGitFactoryMock());
repository.setBasedir(testData.getClonedGit().getGitWorkingDirectory());
repository.setUri(testData.getServerGit().getGitWorkingDirectory().getAbsolutePath().replace("file://", ""));
final AtomicInteger errorCount = new AtomicInteger();
// Prepare two threads to do the parallel work
Thread client = new Thread(new Runnable() {
@Override
public void run() {
logger.info("client start.");
try {
Environment environment = testData.getRepository().findOne("bar", "staging", "master");
} catch (Exception e) {
errorCount.incrementAndGet();
e.printStackTrace();
}
logger.info("client end.");
}
});
Thread refresh = new Thread(new Runnable() {
@Override
public void run() {
try {
logger.info("refresh start.");
testData.getRepository().afterPropertiesSet();
logger.info("refresh end.");
} catch (Exception e) {
errorCount.incrementAndGet();
e.printStackTrace();
}
}
});
// Start the parallel actions and wait till the end.
refresh.start();
client.start();
refresh.join();
client.join();
assertEquals(0, errorCount.get());
}
@Configuration
@EnableConfigurationProperties(ConfigServerProperties.class)
@Import({ PropertyPlaceholderAutoConfiguration.class,
@@ -103,4 +172,80 @@ public class JGitEnvironmentRepositoryConcurrencyTests {
protected static class TestConfiguration {
}
private static class DelayedGitFactoryMock extends JGitEnvironmentRepository.JGitFactory {
@Override
public Git getGitByOpen(File file) throws IOException {
Git originalGit = DelayedGitMock.open(file);
return new DelayedGitMock(originalGit.getRepository());
}
@Override
public CloneCommand getCloneCommandByCloneRepository() {
return new DelayedCloneCommand();
}
}
private static class DelayedGitMock extends Git {
public DelayedGitMock(Repository repo) {
super(repo);
}
@Override
public FetchCommand fetch() {
return new DelayedFetchCommand(getRepository());
}
@Override
public CheckoutCommand checkout() {
return new DelayedCheckoutCommand(getRepository());
}
}
private static class DelayedCloneCommand extends CloneCommand {
@Override
public Git call() throws GitAPIException, InvalidRemoteException, TransportException {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.call();
}
}
private static class DelayedFetchCommand extends FetchCommand {
public DelayedFetchCommand(Repository repo) {
super(repo);
}
@Override
public FetchResult call() throws GitAPIException, InvalidRemoteException, TransportException {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.call();
}
}
private static class DelayedCheckoutCommand extends CheckoutCommand {
public DelayedCheckoutCommand(Repository repo) {
super(repo);
}
@Override
public Ref call() throws GitAPIException, RefAlreadyExistsException, RefNotFoundException, InvalidRefNameException, CheckoutConflictException {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.call();
}
}
}