Move code from spring-boot-actuator to spring-boot-session

This commit is contained in:
Andy Wilkinson
2025-05-12 14:04:39 +01:00
committed by Phillip Webb
parent aea09106f2
commit e2e9000aab
13 changed files with 32 additions and 28 deletions

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;
import org.springframework.session.ReactiveFindByIndexNameSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.Session;
import org.springframework.util.Assert;
/**
* {@link Endpoint @Endpoint} to expose information about HTTP {@link Session}s on a
* reactive stack.
*
* @author Vedran Pavic
* @author Moritz Halbritter
* @since 3.3.0
*/
@Endpoint(id = "sessions")
public class ReactiveSessionsEndpoint {
private final ReactiveSessionRepository<? extends Session> sessionRepository;
private final ReactiveFindByIndexNameSessionRepository<? extends Session> indexedSessionRepository;
/**
* Create a new {@link ReactiveSessionsEndpoint} instance.
* @param sessionRepository the session repository
* @param indexedSessionRepository the indexed session repository
*/
public ReactiveSessionsEndpoint(ReactiveSessionRepository<? extends Session> sessionRepository,
ReactiveFindByIndexNameSessionRepository<? extends Session> indexedSessionRepository) {
Assert.notNull(sessionRepository, "'sessionRepository' must not be null");
this.sessionRepository = sessionRepository;
this.indexedSessionRepository = indexedSessionRepository;
}
@ReadOperation
public Mono<SessionsDescriptor> sessionsForUsername(String username) {
if (this.indexedSessionRepository == null) {
return Mono.empty();
}
return this.indexedSessionRepository.findByPrincipalName(username).map(SessionsDescriptor::new);
}
@ReadOperation
public Mono<SessionDescriptor> getSession(@Selector String sessionId) {
return this.sessionRepository.findById(sessionId).map(SessionDescriptor::new);
}
@DeleteOperation
public Mono<Void> deleteSession(@Selector String sessionId) {
return this.sessionRepository.deleteById(sessionId);
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.session.Session;
/**
* Description of user's {@link Session sessions}.
*
* @author Moritz Halbritter
* @since 3.3.0
*/
public final class SessionsDescriptor implements OperationResponseBody {
private final List<SessionDescriptor> sessions;
public SessionsDescriptor(Map<String, ? extends Session> sessions) {
this.sessions = sessions.values().stream().map(SessionDescriptor::new).toList();
}
public List<SessionDescriptor> getSessions() {
return this.sessions;
}
/**
* A description of user's {@link Session session} exposed by {@code sessions}
* endpoint. Primarily intended for serialization to JSON.
*/
public static final class SessionDescriptor {
private final String id;
private final Set<String> attributeNames;
private final Instant creationTime;
private final Instant lastAccessedTime;
private final long maxInactiveInterval;
private final boolean expired;
SessionDescriptor(Session session) {
this.id = session.getId();
this.attributeNames = session.getAttributeNames();
this.creationTime = session.getCreationTime();
this.lastAccessedTime = session.getLastAccessedTime();
this.maxInactiveInterval = session.getMaxInactiveInterval().getSeconds();
this.expired = session.isExpired();
}
public String getId() {
return this.id;
}
public Set<String> getAttributeNames() {
return this.attributeNames;
}
public Instant getCreationTime() {
return this.creationTime;
}
public Instant getLastAccessedTime() {
return this.lastAccessedTime;
}
public long getMaxInactiveInterval() {
return this.maxInactiveInterval;
}
public boolean isExpired() {
return this.expired;
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.util.Assert;
/**
* {@link Endpoint @Endpoint} to expose information about HTTP {@link Session}s on a
* Servlet stack.
*
* @author Vedran Pavic
* @since 2.0.0
*/
@Endpoint(id = "sessions")
public class SessionsEndpoint {
private final SessionRepository<? extends Session> sessionRepository;
private final FindByIndexNameSessionRepository<? extends Session> indexedSessionRepository;
/**
* Create a new {@link SessionsEndpoint} instance.
* @param sessionRepository the session repository
* @param indexedSessionRepository the indexed session repository
* @since 3.3.0
*/
public SessionsEndpoint(SessionRepository<? extends Session> sessionRepository,
FindByIndexNameSessionRepository<? extends Session> indexedSessionRepository) {
Assert.notNull(sessionRepository, "'sessionRepository' must not be null");
this.sessionRepository = sessionRepository;
this.indexedSessionRepository = indexedSessionRepository;
}
@ReadOperation
public SessionsDescriptor sessionsForUsername(String username) {
if (this.indexedSessionRepository == null) {
return null;
}
Map<String, ? extends Session> sessions = this.indexedSessionRepository.findByPrincipalName(username);
return new SessionsDescriptor(sessions);
}
@ReadOperation
public SessionDescriptor getSession(@Selector String sessionId) {
Session session = this.sessionRepository.findById(sessionId);
if (session == null) {
return null;
}
return new SessionDescriptor(session);
}
@DeleteOperation
public void deleteSession(@Selector String sessionId) {
this.sessionRepository.deleteById(sessionId);
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Actuator endpoint for Spring Session.
*/
package org.springframework.boot.session.actuate.endpoint;

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;
import org.springframework.session.MapSession;
import org.springframework.session.ReactiveFindByIndexNameSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.Session;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ReactiveSessionsEndpoint}.
*
* @author Vedran Pavic
* @author Moritz Halbritter
*/
class ReactiveSessionsEndpointTests {
private static final Session session = new MapSession();
@SuppressWarnings("unchecked")
private final ReactiveSessionRepository<Session> sessionRepository = mock(ReactiveSessionRepository.class);
@SuppressWarnings("unchecked")
private final ReactiveFindByIndexNameSessionRepository<Session> indexedSessionRepository = mock(
ReactiveFindByIndexNameSessionRepository.class);
private final ReactiveSessionsEndpoint endpoint = new ReactiveSessionsEndpoint(this.sessionRepository,
this.indexedSessionRepository);
@Test
void sessionsForUsername() {
given(this.indexedSessionRepository.findByPrincipalName("user"))
.willReturn(Mono.just(Collections.singletonMap(session.getId(), session)));
StepVerifier.create(this.endpoint.sessionsForUsername("user")).consumeNextWith((sessions) -> {
List<SessionDescriptor> result = sessions.getSessions();
assertThat(result).hasSize(1);
assertThat(result.get(0).getId()).isEqualTo(session.getId());
assertThat(result.get(0).getAttributeNames()).isEqualTo(session.getAttributeNames());
assertThat(result.get(0).getCreationTime()).isEqualTo(session.getCreationTime());
assertThat(result.get(0).getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());
assertThat(result.get(0).getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());
assertThat(result.get(0).isExpired()).isEqualTo(session.isExpired());
}).expectComplete().verify(Duration.ofSeconds(1));
then(this.indexedSessionRepository).should().findByPrincipalName("user");
}
@Test
void sessionsForUsernameWhenNoIndexedRepository() {
ReactiveSessionsEndpoint endpoint = new ReactiveSessionsEndpoint(this.sessionRepository, null);
StepVerifier.create(endpoint.sessionsForUsername("user")).expectComplete().verify(Duration.ofSeconds(1));
}
@Test
void getSession() {
given(this.sessionRepository.findById(session.getId())).willReturn(Mono.just(session));
StepVerifier.create(this.endpoint.getSession(session.getId())).consumeNextWith((result) -> {
assertThat(result.getId()).isEqualTo(session.getId());
assertThat(result.getAttributeNames()).isEqualTo(session.getAttributeNames());
assertThat(result.getCreationTime()).isEqualTo(session.getCreationTime());
assertThat(result.getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());
assertThat(result.getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());
assertThat(result.isExpired()).isEqualTo(session.isExpired());
}).expectComplete().verify(Duration.ofSeconds(1));
then(this.sessionRepository).should().findById(session.getId());
}
@Test
void getSessionWithIdNotFound() {
given(this.sessionRepository.findById("not-found")).willReturn(Mono.empty());
StepVerifier.create(this.endpoint.getSession("not-found")).expectComplete().verify(Duration.ofSeconds(1));
then(this.sessionRepository).should().findById("not-found");
}
@Test
void deleteSession() {
given(this.sessionRepository.deleteById(session.getId())).willReturn(Mono.empty());
StepVerifier.create(this.endpoint.deleteSession(session.getId()))
.expectComplete()
.verify(Duration.ofSeconds(1));
then(this.sessionRepository).should().deleteById(session.getId());
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import java.util.Collections;
import net.minidev.json.JSONArray;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.MapSession;
import org.springframework.session.ReactiveFindByIndexNameSessionRepository;
import org.springframework.session.ReactiveSessionRepository;
import org.springframework.session.Session;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Integration tests for {@link ReactiveSessionsEndpoint} exposed by WebFlux.
*
* @author Vedran Pavic
* @author Moritz Halbritter
*/
class ReactiveSessionsEndpointWebIntegrationTests {
private static final Session session = new MapSession();
@SuppressWarnings("unchecked")
private static final ReactiveSessionRepository<Session> sessionRepository = mock(ReactiveSessionRepository.class);
@SuppressWarnings("unchecked")
private static final ReactiveFindByIndexNameSessionRepository<Session> indexedSessionRepository = mock(
ReactiveFindByIndexNameSessionRepository.class);
@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)
void sessionsForUsernameWithoutUsernameParam(WebTestClient client) {
client.get()
.uri((builder) -> builder.path("/actuator/sessions").build())
.exchange()
.expectStatus()
.is4xxClientError();
}
@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)
void sessionsForUsernameNoResults(WebTestClient client) {
given(indexedSessionRepository.findByPrincipalName("user")).willReturn(Mono.just(Collections.emptyMap()));
client.get()
.uri((builder) -> builder.path("/actuator/sessions").queryParam("username", "user").build())
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("sessions")
.isEmpty();
}
@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)
void sessionsForUsernameFound(WebTestClient client) {
given(indexedSessionRepository.findByPrincipalName("user"))
.willReturn(Mono.just(Collections.singletonMap(session.getId(), session)));
client.get()
.uri((builder) -> builder.path("/actuator/sessions").queryParam("username", "user").build())
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("sessions.[*].id")
.isEqualTo(new JSONArray().appendElement(session.getId()));
}
@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)
void sessionForIdFound(WebTestClient client) {
given(sessionRepository.findById(session.getId())).willReturn(Mono.just(session));
client.get()
.uri((builder) -> builder.path("/actuator/sessions/{id}").build(session.getId()))
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("id")
.isEqualTo(session.getId());
}
@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)
void sessionForIdNotFound(WebTestClient client) {
given(sessionRepository.findById("not-found")).willReturn(Mono.empty());
client.get()
.uri((builder) -> builder.path("/actuator/sessions/not-found").build())
.exchange()
.expectStatus()
.isNotFound();
}
@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)
void deleteSession(WebTestClient client) {
given(sessionRepository.deleteById(session.getId())).willReturn(Mono.empty());
client.delete()
.uri((builder) -> builder.path("/actuator/sessions/{id}").build(session.getId()))
.exchange()
.expectStatus()
.isNoContent();
}
@Configuration(proxyBeanMethods = false)
static class TestConfiguration {
@Bean
ReactiveSessionsEndpoint sessionsEndpoint() {
return new ReactiveSessionsEndpoint(sessionRepository, indexedSessionRepository);
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link SessionsEndpoint}.
*
* @author Vedran Pavic
*/
class SessionsEndpointTests {
private static final Session session = new MapSession();
@SuppressWarnings("unchecked")
private final SessionRepository<Session> sessionRepository = mock(SessionRepository.class);
@SuppressWarnings("unchecked")
private final FindByIndexNameSessionRepository<Session> indexedSessionRepository = mock(
FindByIndexNameSessionRepository.class);
private final SessionsEndpoint endpoint = new SessionsEndpoint(this.sessionRepository,
this.indexedSessionRepository);
@Test
void sessionsForUsername() {
given(this.indexedSessionRepository.findByPrincipalName("user"))
.willReturn(Collections.singletonMap(session.getId(), session));
List<SessionDescriptor> result = this.endpoint.sessionsForUsername("user").getSessions();
assertThat(result).hasSize(1);
assertThat(result.get(0).getId()).isEqualTo(session.getId());
assertThat(result.get(0).getAttributeNames()).isEqualTo(session.getAttributeNames());
assertThat(result.get(0).getCreationTime()).isEqualTo(session.getCreationTime());
assertThat(result.get(0).getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());
assertThat(result.get(0).getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());
assertThat(result.get(0).isExpired()).isEqualTo(session.isExpired());
then(this.indexedSessionRepository).should().findByPrincipalName("user");
}
@Test
void sessionsForUsernameWhenNoIndexedRepository() {
SessionsEndpoint endpoint = new SessionsEndpoint(this.sessionRepository, null);
assertThat(endpoint.sessionsForUsername("user")).isNull();
}
@Test
void getSession() {
given(this.sessionRepository.findById(session.getId())).willReturn(session);
SessionDescriptor result = this.endpoint.getSession(session.getId());
assertThat(result.getId()).isEqualTo(session.getId());
assertThat(result.getAttributeNames()).isEqualTo(session.getAttributeNames());
assertThat(result.getCreationTime()).isEqualTo(session.getCreationTime());
assertThat(result.getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());
assertThat(result.getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());
assertThat(result.isExpired()).isEqualTo(session.isExpired());
then(this.sessionRepository).should().findById(session.getId());
}
@Test
void getSessionWithIdNotFound() {
given(this.sessionRepository.findById("not-found")).willReturn(null);
assertThat(this.endpoint.getSession("not-found")).isNull();
then(this.sessionRepository).should().findById("not-found");
}
@Test
void deleteSession() {
this.endpoint.deleteSession(session.getId());
then(this.sessionRepository).should().deleteById(session.getId());
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2012-2025 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 org.springframework.boot.session.actuate.endpoint;
import java.util.Collections;
import net.minidev.json.JSONArray;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Integration tests for {@link SessionsEndpoint} exposed by Jersey, Spring MVC, and
* WebFlux.
*
* @author Vedran Pavic
*/
class SessionsEndpointWebIntegrationTests {
private static final Session session = new MapSession();
@SuppressWarnings("unchecked")
private static final FindByIndexNameSessionRepository<Session> repository = mock(
FindByIndexNameSessionRepository.class);
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
void sessionsForUsernameWithoutUsernameParam(WebTestClient client) {
client.get()
.uri((builder) -> builder.path("/actuator/sessions").build())
.exchange()
.expectStatus()
.isBadRequest();
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
void sessionsForUsernameNoResults(WebTestClient client) {
given(repository.findByPrincipalName("user")).willReturn(Collections.emptyMap());
client.get()
.uri((builder) -> builder.path("/actuator/sessions").queryParam("username", "user").build())
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("sessions")
.isEmpty();
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
void sessionsForUsernameFound(WebTestClient client) {
given(repository.findByPrincipalName("user")).willReturn(Collections.singletonMap(session.getId(), session));
client.get()
.uri((builder) -> builder.path("/actuator/sessions").queryParam("username", "user").build())
.exchange()
.expectStatus()
.isOk()
.expectBody()
.jsonPath("sessions.[*].id")
.isEqualTo(new JSONArray().appendElement(session.getId()));
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
void sessionForIdNotFound(WebTestClient client) {
client.get()
.uri((builder) -> builder.path("/actuator/sessions/session-id-not-found").build())
.exchange()
.expectStatus()
.isNotFound();
}
@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })
void deleteSession(WebTestClient client) {
client.delete()
.uri((builder) -> builder.path("/actuator/sessions/{id}").build(session.getId()))
.exchange()
.expectStatus()
.isNoContent();
}
@Configuration(proxyBeanMethods = false)
static class TestConfiguration {
@Bean
SessionsEndpoint sessionsEndpoint() {
return new SessionsEndpoint(repository, repository);
}
}
}