Send 404 if application not found (#960)

Send 404 if application not found and `spring.cloud.config.server.accept-emtpy=true`

Fixes gh-155
This commit is contained in:
Chidambaram Sundaram
2018-04-11 07:11:09 +05:30
committed by Spencer Gibb
parent e049cfd818
commit c70bca5149
7 changed files with 117 additions and 19 deletions

View File

@@ -105,6 +105,7 @@ If there are profile-specific YAML (or properties) files, these are also applied
Higher precedence translates to a `PropertySource` listed earlier in the `Environment`.
(These same rules apply in a standalone Spring Boot application.)
You can set spring.cloud.config.server.accept-empty to false so that Server would return a HTTP 404 status, if the application is not found.By default, this flag is set to true.
==== Git Backend
The default implementation of `EnvironmentRepository` uses a Git backend, which is very convenient for managing upgrades and physical

View File

@@ -57,6 +57,7 @@ public class ConfigServerMvcConfiguration extends WebMvcConfigurerAdapter {
public EnvironmentController environmentController(EnvironmentRepository envRepository, ConfigServerProperties server) {
EnvironmentController controller = new EnvironmentController(encrypted(envRepository, server), this.objectMapper);
controller.setStripDocumentFromYaml(server.isStripDocumentFromYaml());
controller.setAcceptEmpty(server.isAcceptEmpty());
return controller;
}

View File

@@ -56,6 +56,10 @@ public class ConfigServerProperties {
* should be returned in "native" form.
*/
private boolean stripDocumentFromYaml = true;
/**
* Flag to indicate that If HTTP 404 needs to be sent if Application is not Found
*/
private boolean acceptEmpty = true;
/**
* Default application name when incoming requests do not have a specific one.
@@ -115,7 +119,14 @@ public class ConfigServerProperties {
public void setStripDocumentFromYaml(boolean stripDocumentFromYaml) {
this.stripDocumentFromYaml = stripDocumentFromYaml;
}
public boolean isAcceptEmpty() {
return this.acceptEmpty;
}
public void setAcceptEmpty(boolean acceptEmpty) {
this.acceptEmpty = acceptEmpty;
}
public String getDefaultApplicationName() {
return this.defaultApplicationName;
}

View File

@@ -69,6 +69,7 @@ public class EnvironmentController {
private ObjectMapper objectMapper;
private boolean stripDocument = true;
private boolean acceptEmpty = true;
public EnvironmentController(EnvironmentRepository repository) {
this(repository, new ObjectMapper());
@@ -90,6 +91,15 @@ public class EnvironmentController {
this.stripDocument = stripDocument;
}
/**
* Flag to indicate that If HTTP 404 needs to be sent if Application is not Found
*
* @param acceptEmpty the flag to set
*/
public void setAcceptEmpty(boolean acceptEmpty) {
this.acceptEmpty = acceptEmpty;
}
@RequestMapping("/{name}/{profiles:.*[^-].*}")
public Environment defaultLabel(@PathVariable String name,
@PathVariable String profiles) {
@@ -110,6 +120,9 @@ public class EnvironmentController {
label = label.replace("(_)", "/");
}
Environment environment = this.repository.findOne(name, profiles, label);
if(!acceptEmpty && (environment == null || environment.getPropertySources().isEmpty())){
throw new EnvironmentNotFoundException("Profile Not found");
}
return environment;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2018 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.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* @author Chids
*
*/
@SuppressWarnings("serial")
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Application Not Found")
public class EnvironmentNotFoundException extends RuntimeException {
public EnvironmentNotFoundException(String string) {
super(string);
}
}

View File

@@ -16,16 +16,17 @@
package org.springframework.cloud.config.server.environment;
import java.util.HashMap;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.config.environment.Environment;
import org.springframework.cloud.config.environment.PropertySource;
import org.springframework.cloud.config.server.environment.EnvironmentControllerIntegrationTests.ControllerConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -52,23 +53,26 @@ public class EnvironmentControllerIntegrationTests {
private MockMvc mvc;
@Autowired
private EnvironmentRepository repository;
private Environment environment = new Environment("foo", "default");
@Before
public void init() {
Mockito.reset(this.repository);
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
environment.add(new PropertySource("foo", new HashMap<>()));
}
@Test
public void environmentNoLabel() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", null)).thenReturn(new Environment("foo", "default"));
Mockito.when(this.repository.findOne("foo", "default", null)).thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/foo/default")).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(this.repository).findOne("foo", "default", null);
}
@Test
public void propertiesNoLabel() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", null)).thenReturn(new Environment("foo", "default"));
Mockito.when(this.repository.findOne("foo", "default", null)).thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/foo-default.properties"))
.andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(this.repository).findOne("foo", "default", null);
@@ -76,7 +80,7 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void propertiesLabel() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", "label")).thenReturn(new Environment("foo", "default"));
Mockito.when(this.repository.findOne("foo", "default", "label")).thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/label/foo-default.properties"))
.andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(this.repository).findOne("foo", "default", "label");
@@ -84,8 +88,10 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void propertiesLabelWhenApplicationNameContainsHyphen() throws Exception {
Environment environment = new Environment("foo-bar", "default");
environment.add(new PropertySource("foo", new HashMap<>()));
Mockito.when(this.repository.findOne("foo-bar", "default", "label"))
.thenReturn(new Environment("foo-bar", "default"));
.thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/label/foo-bar-default.properties"))
.andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(this.repository).findOne("foo-bar", "default", "label");
@@ -93,8 +99,9 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void propertiesLabelWithSlash() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", "label/spam"))
.thenReturn(new Environment("foo", "default"));
.thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/label(_)spam/foo-default.properties"))
.andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(this.repository).findOne("foo", "default", "label/spam");
@@ -103,7 +110,7 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void environmentWithLabel() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", "awesome"))
.thenReturn(new Environment("foo", "default"));
.thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/foo/default/awesome"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
@@ -126,7 +133,7 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void environmentWithLabelContainingPeriod() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", "1.0.0")).thenReturn(new Environment("foo", "default"));
Mockito.when(this.repository.findOne("foo", "default", "1.0.0")).thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/foo/default/1.0.0"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
@@ -134,7 +141,7 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void environmentWithLabelContainingSlash() throws Exception {
Mockito.when(this.repository.findOne("foo", "default", "feature/puff"))
.thenReturn(new Environment("foo", "default"));
.thenReturn(this.environment);
this.mvc.perform(MockMvcRequestBuilders.get("/foo/default/feature(_)puff"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("\"propertySources\":")));
@@ -142,8 +149,10 @@ public class EnvironmentControllerIntegrationTests {
@Test
public void environmentWithApplicationContainingSlash() throws Exception {
Environment environment = new Environment("foo/app", "default");
environment.add(new PropertySource("foo", new HashMap<>()));
Mockito.when(this.repository.findOne("foo/app", "default", null))
.thenReturn(new Environment("foo/app", "default"));
.thenReturn(environment);
this.mvc.perform(MockMvcRequestBuilders.get("/foo(_)app/default"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("\"propertySources\":")));

View File

@@ -65,6 +65,7 @@ public class EnvironmentControllerTests {
@Before
public void init() {
this.controller = new EnvironmentController(this.repository);
environment.add(new PropertySource("foo", new HashMap<>()));
}
@After
@@ -195,27 +196,47 @@ public class EnvironmentControllerTests {
assertThat(environment.getProfiles(), equalTo(new String[] { "master" }));
assertThat(environment.getLabel(), equalTo("master"));
assertThat(environment.getVersion(), nullValue());
assertThat(environment.getPropertySources(), hasSize(2));
assertThat(environment.getPropertySources(), hasSize(3));
assertThat(environment.getPropertySources().get(0).getName(), equalTo("two"));
assertThat(environment.getPropertySources().get(0).getSource().entrySet(),
hasSize(2));
assertThat(environment.getPropertySources().get(1).getName(), equalTo("one"));
assertThat(environment.getPropertySources().get(1).getSource().entrySet(),
assertThat(environment.getPropertySources().get(2).getName(), equalTo("one"));
assertThat(environment.getPropertySources().get(2).getSource().entrySet(),
hasSize(3));
}
@Test
public void testNameWithSlash() {
this.controller.labelled("foo(_)spam", "bar", "two");
Mockito.verify(this.repository).findOne("foo/spam", "bar", "two");
}
Mockito.when(this.repository.findOne("foo/spam", "bar", "two")).thenReturn(this.environment);
Environment returnedEnvironment = this.controller.labelled("foo(_)spam", "bar", "two");
assertEquals(this.environment.getLabel(), returnedEnvironment.getLabel());
assertEquals(this.environment.getName(), returnedEnvironment.getName());
}
@Test(expected=EnvironmentNotFoundException.class)
public void testEnvironmentNotFound() {
this.controller.setAcceptEmpty(false);
this.controller.labelled("foo", "bar", null);
}
@Test
public void testwithValidEnvironment() {
Mockito.when(this.repository.findOne("foo", "bar",null))
.thenReturn(this.environment);
Environment environment = this.controller.labelled("foo", "bar", null);
assertThat(environment, not(nullValue()));
}
@Test
public void testLabelWithSlash() {
this.controller.labelled("foo", "bar", "two(_)spam");
Mockito.verify(this.repository).findOne("foo", "bar", "two/spam");
Mockito.when(this.repository.findOne("foo", "bar", "two/spam")).thenReturn(this.environment);
Environment returnedEnvironment = this.controller.labelled("foo", "bar", "two(_)spam");
assertEquals(this.environment.getLabel(), returnedEnvironment.getLabel());
assertEquals(this.environment.getName(), returnedEnvironment.getName());
}
@Test
@@ -491,6 +512,15 @@ public class EnvironmentControllerTests {
mvc.perform(MockMvcRequestBuilders.get("/foo/bar/other"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
@Test
public void environmentMissing() throws Exception {
Mockito.when(this.repository.findOne("foo1", "notfound", null))
.thenThrow(new EnvironmentNotFoundException("Missing Environment"));
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
mvc.perform(MockMvcRequestBuilders.get("/foo1/notfound"))
.andExpect(MockMvcResultMatchers.status().isNotFound());
}
@Test
public void mappingForYaml() throws Exception {