/* * Copyright 2017-2019 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 * * https://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.example; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.concurrent.TimeUnit; import org.awaitility.Awaitility; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.hamcrest.Matchers.is; import static org.junit.Assume.assumeThat; /** * Integration test for the config client with local config server. * * <p>Because the test brings in config server/config client source files into a single project, * config server bootstrap need to be suppressed in the config client app instance. * * @author Elena Felder * * @since 1.2 */ public class LocalSampleAppIntegrationTest { static final String CONFIG_DIR = "/tmp/config"; static final String CONFIG_FILE = CONFIG_DIR + "/application.properties"; static final String INITIAL_MESSAGE = "initial message"; static final String UPDATED_MESSAGE = "updated message"; final RestTemplate restTemplate = new RestTemplate(); BufferedReader configServerOutput; BufferedReader configClientOutput; Process configServerProcess; Process configClientProcess; @BeforeClass public static void prepare() throws Exception { assumeThat( "PUB/SUB integration tests are disabled. Use '-Dit.pubsub=true' to enable.", System.getProperty("it.pubsub"), is("true")); Files.createDirectories(Paths.get(CONFIG_DIR)); } @Test public void testSample() throws Exception { writeMessageToFile(INITIAL_MESSAGE); startConfigServer(); waitForLogMessage(this.configServerOutput, "Monitoring for local config changes: [" + CONFIG_DIR + "]"); waitForLogMessage(this.configServerOutput, "Started PubSubConfigServerApplication"); assertConfigServerValue(INITIAL_MESSAGE); startConfigClient(); waitForLogMessage(this.configClientOutput, "Located property source"); waitForLogMessage(this.configClientOutput, "Started PubSubConfigApplication"); assertConfigClientValue(INITIAL_MESSAGE); writeMessageToFile(UPDATED_MESSAGE); waitForLogMessage(this.configServerOutput, "Refresh for: *"); assertConfigServerValue(UPDATED_MESSAGE); waitForLogMessage(this.configClientOutput, "Keys refreshed [example.message]"); assertConfigClientValue(UPDATED_MESSAGE); } @AfterClass public static void tearDown() throws Exception { Path configFile = Paths.get(CONFIG_FILE); if (Files.exists(configFile)) { Files.delete(configFile); } Path configDir = Paths.get(CONFIG_DIR); if (Files.exists(configDir)) { Files.delete(configDir); } } @After public void closeResources() throws IOException { if (this.configServerOutput != null) { this.configServerOutput.close(); } if (this.configClientOutput != null) { this.configClientOutput.close(); } if (this.configServerProcess != null) { this.configServerProcess.destroy(); } if (this.configClientProcess != null) { this.configClientProcess.destroy(); } } private void startConfigServer() throws IOException { ProcessBuilder serverBuilder = new ProcessBuilder("mvn", "spring-boot:run", "-f", "../spring-cloud-gcp-pubsub-bus-config-sample-server-local"); this.configServerProcess = serverBuilder.start(); this.configServerOutput = new BufferedReader(new InputStreamReader(this.configServerProcess.getInputStream())); } private void startConfigClient() throws IOException { ProcessBuilder serverBuilder = new ProcessBuilder("mvn", "spring-boot:run", "-f", "../spring-cloud-gcp-pubsub-bus-config-sample-client"); this.configClientProcess = serverBuilder.start(); this.configClientOutput = new BufferedReader(new InputStreamReader(this.configClientProcess.getInputStream())); } private static void writeMessageToFile(String value) { File properties = new File(CONFIG_FILE); try (FileOutputStream fos = new FileOutputStream(properties)) { fos.write(("example.message = " + value).getBytes()); } catch (IOException e) { fail("Could not write message to file", e); } } private void assertConfigServerValue(String message) { // Server is aware of value from filesystem. String serverPropertiesJson = this.restTemplate.getForObject("http://localhost:8888/application/default", String.class); assertThat(serverPropertiesJson).contains(message); } private void assertConfigClientValue(String message) { // Refresh scoped variable updated and returned. String value = this.restTemplate.getForObject("http://localhost:8080/message", String.class); assertThat(value).isEqualTo(message); } private void waitForLogMessage(BufferedReader reader, String message) { Awaitility.await(message) .atMost(60, TimeUnit.SECONDS) .until(() -> { // drain all lines up to the one requested, or until no more lines in reader. while (reader.ready()) { String line = reader.readLine(); if (line == null) { return false; } if (line.contains(message)) { return true; } } return false; }); } }