From b268963025614c44260eb2dd2cc97c9d53d41b88 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 22 Feb 2016 14:03:26 +0000 Subject: [PATCH] Let MVC handle content negotiation for endpoints In particular the ResourceEndpoint is likely to serve data that is not JSON, so having a "produces" attribute at the type level is a bad idea. Fixes gh-337 --- .../config/monitor/PropertyPathEndpoint.java | 4 +- .../encryption/EncryptionController.java | 4 +- .../environment/EnvironmentController.java | 2 +- .../server/resource/ResourceController.java | 2 +- .../ResourceControllerIntegrationTests.java | 100 ++++++++++++++++++ 5 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerIntegrationTests.java diff --git a/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/PropertyPathEndpoint.java b/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/PropertyPathEndpoint.java index 28f16f36..9f554636 100644 --- a/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/PropertyPathEndpoint.java +++ b/spring-cloud-config-monitor/src/main/java/org/springframework/cloud/config/monitor/PropertyPathEndpoint.java @@ -51,7 +51,7 @@ import lombok.extern.apachecommons.CommonsLog; */ @RequiredArgsConstructor @RestController -@RequestMapping(path = "${spring.cloud.config.monitor.endpoint.path:}/monitor", produces = MediaType.APPLICATION_JSON_VALUE) +@RequestMapping(path = "${spring.cloud.config.monitor.endpoint.path:}/monitor") @CommonsLog public class PropertyPathEndpoint implements ApplicationEventPublisherAware, ApplicationContextAware { @@ -116,7 +116,7 @@ public class PropertyPathEndpoint int index = stem.indexOf("-"); while (index >= 0) { String name = stem.substring(0, index); - String profile = stem.substring(index+1); + String profile = stem.substring(index + 1); if ("application".equals(name)) { services.add("*:" + profile); } diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/encryption/EncryptionController.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/encryption/EncryptionController.java index dbea5207..99825320 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/encryption/EncryptionController.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/encryption/EncryptionController.java @@ -45,7 +45,7 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -@RequestMapping(path = "${spring.cloud.config.server.prefix:}", produces = MediaType.APPLICATION_JSON_VALUE) +@RequestMapping(path = "${spring.cloud.config.server.prefix:}") public class EncryptionController { private static Log logger = LogFactory.getLog(EncryptionController.class); @@ -111,7 +111,7 @@ public class EncryptionController { @RequestMapping(value = "encrypt/status", method = RequestMethod.GET) public Map status() { checkEncryptorInstalled("application", "default"); - return Collections. singletonMap("status", "OK"); + return Collections.singletonMap("status", "OK"); } @RequestMapping(value = "encrypt", method = RequestMethod.POST) diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/EnvironmentController.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/EnvironmentController.java index 37fb6bed..2006d7e4 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/EnvironmentController.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/EnvironmentController.java @@ -57,7 +57,7 @@ import org.yaml.snakeyaml.nodes.Tag; * */ @RestController -@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}", produces = MediaType.APPLICATION_JSON_VALUE) +@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}") public class EnvironmentController { private static final String MAP_PREFIX = "map"; diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java index c545f74b..960bb0a3 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java @@ -48,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController; * */ @RestController -@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}", produces = MediaType.APPLICATION_JSON_VALUE) +@RequestMapping(method = RequestMethod.GET, path = "${spring.cloud.config.server.prefix:}") public class ResourceController { private ResourceRepository resourceRepository; diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerIntegrationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerIntegrationTests.java new file mode 100644 index 00000000..6a69b5ee --- /dev/null +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerIntegrationTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2013-2015 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.resource; + +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.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.cloud.config.environment.Environment; +import org.springframework.cloud.config.server.environment.EnvironmentRepository; +import org.springframework.cloud.config.server.resource.ResourceControllerIntegrationTests.ControllerConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +/** + * @author Dave Syer + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = ControllerConfiguration.class) +@WebAppConfiguration +public class ResourceControllerIntegrationTests { + + @Autowired + private WebApplicationContext context; + private MockMvc mvc; + @Autowired + private EnvironmentRepository repository; + @Autowired + private ResourceRepository resources; + + @Before + public void init() { + Mockito.reset(this.repository); + this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build(); + } + + @Test + public void environmentNoLabel() throws Exception { + Mockito.when(this.repository.findOne("foo", "default", "master")) + .thenReturn(new Environment("foo", "default")); + Mockito.when(this.resources.findOne("foo", "default", "master", "foo.txt")) + .thenReturn(new ByteArrayResource("hello".getBytes())); + this.mvc.perform(MockMvcRequestBuilders.get("/foo/default/master/foo.txt")) + .andExpect(MockMvcResultMatchers.status().isOk()); + Mockito.verify(this.repository).findOne("foo", "default", "master"); + Mockito.verify(this.resources).findOne("foo", "default", "master", "foo.txt"); + } + + @Configuration + @EnableWebMvc + @Import(PropertyPlaceholderAutoConfiguration.class) + public static class ControllerConfiguration { + + @Bean + public EnvironmentRepository environmentRepository() { + EnvironmentRepository repository = Mockito.mock(EnvironmentRepository.class); + return repository; + } + + @Bean + public ResourceRepository resourceRepository() { + ResourceRepository repository = Mockito.mock(ResourceRepository.class); + return repository; + } + + @Bean + public ResourceController controller() { + return new ResourceController(resourceRepository(), environmentRepository()); + } + + } + +}