Skip to content

Commit

Permalink
Merge pull request #9 from pavelfomin/feature/custom-actuator
Browse files Browse the repository at this point in the history
custom actuator
  • Loading branch information
pavelfomin committed Jan 25, 2022
2 parents 0a12f04 + a941d62 commit aaf10c4
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 6 deletions.
1 change: 0 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ dependencies {

testImplementation "org.springframework.boot:spring-boot-starter-test"
testImplementation "org.springframework.security:spring-security-test"
testImplementation "org.hamcrest:hamcrest:2.2"
}

repositories {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=2.5.9.2
version=2.5.9.3

springBootVersion=2.5.9
springBootDependencyManagement=1.0.11.RELEASE
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.droidablebee</groupId>
<artifactId>spring-boot-rest-example</artifactId>
<version>2.5.9.2</version>
<version>2.5.9.3</version>
<name>Spring boot example with REST and spring data JPA</name>

<packaging>jar</packaging>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import org.springframework.http.MediaType;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
public class WebConfiguration implements WebMvcConfigurer {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.droidablebee.springboot.rest.endpoint;

import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;

/**
* Custom actuator endpoint.
*/
@Component
@Endpoint(id = CustomActuatorEndpoint.CUSTOM)
public class CustomActuatorEndpoint {

static final String CUSTOM = "custom";

@ReadOperation
public ResponseEntity<?> custom() {

return ResponseEntity.ok(createCustomMap());
}

protected LinkedMultiValueMap<String, Number> createCustomMap() {

return new LinkedMultiValueMap<>();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.droidablebee.springboot.rest.endpoint;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
import org.springframework.boot.actuate.info.InfoEndpoint;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;

import java.util.HashMap;
import java.util.Map;

@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {

@Autowired
private InfoEndpoint delegate;

@ReadOperation
public WebEndpointResponse<Map<String, ?>> info() {

Map<String, Object> info = new HashMap<>();

//add existing values from unmodifiable map
info.putAll(this.delegate.info());

info.putAll(createCustomMap());

return new WebEndpointResponse<>(info);
}

protected LinkedMultiValueMap<String, Number> createCustomMap() {

return new LinkedMultiValueMap<>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.droidablebee.springboot.rest.endpoint;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.util.LinkedMultiValueMap;

import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isA;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
public class ActuatorEndpointStubbedTest extends BaseEndpointTest {

@SpyBean
private CustomActuatorEndpoint customActuatorEndpoint;

@SpyBean
private InfoWebEndpointExtension infoWebEndpointExtension;

@Test
public void getCustomAuthorized() throws Exception {

LinkedMultiValueMap<String, Number> custom = new LinkedMultiValueMap<>();
custom.add("custom1", 11);
custom.add("custom1", 12);
custom.add("custom2", 21);

when(customActuatorEndpoint.createCustomMap()).thenReturn(custom);

mockMvc.perform(get("/actuator/" + CustomActuatorEndpoint.CUSTOM).with(jwt()))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(JSON_MEDIA_TYPE))
.andExpect(jsonPath("$.custom1", is(custom.get("custom1"))))
.andExpect(jsonPath("$.custom2", is(custom.get("custom2"))))
;
}

@Test
public void getInfoExtended() throws Exception {

LinkedMultiValueMap<String, Number> custom = new LinkedMultiValueMap<>();
custom.add("custom1", 11);
custom.add("custom1", 12);
custom.add("custom2", 21);

when(infoWebEndpointExtension.createCustomMap()).thenReturn(custom);

mockMvc.perform(get("/actuator/info"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(JSON_MEDIA_TYPE))
.andExpect(jsonPath("$.build", isA(Object.class)))
.andExpect(jsonPath("$.build.version", isA(String.class)))
.andExpect(jsonPath("$.build.artifact", is("spring-boot-rest-example")))
.andExpect(jsonPath("$.build.group", is("com.droidablebee")))
.andExpect(jsonPath("$.build.time", isA(Number.class)))
.andExpect(jsonPath("$.custom1", is(custom.get("custom1"))))
.andExpect(jsonPath("$.custom2", is(custom.get("custom2"))))
;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,24 @@ public void getEnvAuthorized() throws Exception {
;
}

@Test
public void getCustom() throws Exception {

mockMvc.perform(get("/actuator/"+ CustomActuatorEndpoint.CUSTOM))
.andDo(print())
.andExpect(status().isUnauthorized())
;
}

@Test
public void getCustomAuthorized() throws Exception {

mockMvc.perform(get("/actuator/"+ CustomActuatorEndpoint.CUSTOM).with(jwt()))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(JSON_MEDIA_TYPE))
.andExpect(content().string("{}"))
;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

@SpringBootTest
@Transactional
public class PersonEndpointMockedTest extends BaseEndpointTest {
public class PersonEndpointStubbedTest extends BaseEndpointTest {

@MockBean
private PersonService personService;
Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/application-default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ management:
endpoints:
web:
exposure:
include: info,health,env
include: info,health,env,custom

0 comments on commit aaf10c4

Please sign in to comment.