Skip to content

Commit

Permalink
Upgrade to Spring Boot 3.4.0-M3 (#6687)
Browse files Browse the repository at this point in the history
#### What type of PR is this?

/kind cleanup
/area core
/milestone 2.20.x

#### What this PR does / why we need it:

This PR upgrades to [Spring Boot 3.4.0-M3](https://github.com/spring-projects/spring-boot/releases/tag/v3.4.0-M3).

1. Fix the compilation error of OptimalPropertyAccess because the class has been privated in [this commit](spring-projects/spring-framework@b431594).
2. Fix exception `org.mockito.exceptions.misusing.UnnecessaryStubbingException` for some unit tests after upgrading.
3. Replace deprecated annotations `@MockBean` and `@SpyBean` with `@MockitoBean` and `@MockitoSpyBean` respectively.

#### Does this PR introduce a user-facing change?

```release-note
升级 Spring Boot 至 3.4.0-M3
```
  • Loading branch information
JohnNiang authored Sep 24, 2024
1 parent 035207b commit 86b95cc
Show file tree
Hide file tree
Showing 22 changed files with 140 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.expression.MethodResolver;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CompilablePropertyAccessor;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.integration.json.JsonPropertyAccessor;
import org.springframework.lang.Nullable;
Expand Down Expand Up @@ -122,7 +123,7 @@ public Class<?>[] getSpecificTargetClasses() {
public PropertyAccessor createOptimalAccessor(EvaluationContext context, Object target,
String name) {
var optimalAccessor = delegate.createOptimalAccessor(context, target, name);
if (optimalAccessor instanceof OptimalPropertyAccessor optimalPropertyAccessor) {
if (optimalAccessor instanceof CompilablePropertyAccessor optimalPropertyAccessor) {
if (ReactiveUtils.isReactiveType(optimalPropertyAccessor.getPropertyType())) {
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import run.halo.app.core.extension.Role;
Expand All @@ -47,7 +47,7 @@ class ExtensionConfigurationTest {
@Autowired
SchemeManager schemeManager;

@MockBean
@MockitoBean
RoleService roleService;

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
Expand All @@ -38,7 +38,7 @@ class WebFluxConfigTest {
@Autowired
WebTestClient webClient;

@SpyBean
@MockitoSpyBean
RoleService roleService;

@LocalServerPort
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
Expand Down Expand Up @@ -46,7 +46,7 @@ class CategoryPostCountServiceIntegrationTest {
@Autowired
private SchemeManager schemeManager;

@SpyBean
@MockitoSpyBean
private ExtensionClient client;

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import run.halo.app.core.extension.Role;
Expand All @@ -39,7 +39,7 @@ public class PostIntegrationTests {
@Autowired
private WebTestClient webTestClient;

@MockBean
@MockitoBean
RoleService roleService;

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
Expand Down Expand Up @@ -48,7 +48,7 @@ class CommentRemoveTest {
@Autowired
private SchemeManager schemeManager;

@SpyBean
@MockitoSpyBean
private ReactiveExtensionClient reactiveClient;

@Autowired
Expand All @@ -57,7 +57,7 @@ class CommentRemoveTest {
@Autowired
private IndexerFactory indexerFactory;

@SpyBean
@MockitoSpyBean
private CommentServiceImpl commentService;

Mono<Extension> deleteImmediately(Extension extension) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand All @@ -12,7 +11,6 @@
import java.util.Map;
import java.util.Set;
import org.json.JSONException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
Expand Down Expand Up @@ -61,53 +59,25 @@
class CommentServiceImplTest {

@Mock
private SystemConfigurableEnvironmentFetcher environmentFetcher;
SystemConfigurableEnvironmentFetcher environmentFetcher;

@Mock
private ReactiveExtensionClient client;
ReactiveExtensionClient client;

@Mock
private UserService userService;
UserService userService;

@Mock
private RoleService roleService;
RoleService roleService;

@Mock
private ExtensionGetter extensionGetter;
ExtensionGetter extensionGetter;

@InjectMocks
private CommentServiceImpl commentService;
CommentServiceImpl commentService;

@Mock
private CounterService counterService;

@BeforeEach
void setUp() {
SystemSetting.Comment commentSetting = getCommentSetting();
lenient().when(environmentFetcher.fetchComment()).thenReturn(Mono.just(commentSetting));

ListResult<Comment> comments = new ListResult<>(1, 10, 3, comments());
when(client.listBy(eq(Comment.class), any(ListOptions.class), any(PageRequest.class)))
.thenReturn(Mono.just(comments));

when(userService.getUserOrGhost(eq("A-owner")))
.thenReturn(Mono.just(createUser("A-owner")));
when(userService.getUserOrGhost(eq("B-owner")))
.thenReturn(Mono.just(createUser("B-owner")));
when(client.fetch(eq(User.class), eq("C-owner")))
.thenReturn(Mono.empty());

when(roleService.contains(Set.of("USER"),
Set.of(AuthorityUtils.COMMENT_MANAGEMENT_ROLE_NAME)))
.thenReturn(Mono.just(false));

PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class);
when(extensionGetter.getExtensions(CommentSubject.class))
.thenReturn(Flux.just(postCommentSubject));

when(postCommentSubject.supports(any())).thenReturn(true);
when(postCommentSubject.get(eq("fake-post"))).thenReturn(Mono.just(post()));
}
CounterService counterService;

private static User createUser(String name) {
User user = new User();
Expand All @@ -122,10 +92,21 @@ private static User createUser(String name) {

@Test
void listComment() {
var comments = new ListResult<Comment>(1, 10, 3, comments());
when(client.listBy(eq(Comment.class), any(ListOptions.class), any(PageRequest.class)))
.thenReturn(Mono.just(comments));

PostCommentSubject postCommentSubject = Mockito.mock(PostCommentSubject.class);
when(extensionGetter.getExtensions(CommentSubject.class))
.thenReturn(Flux.just(postCommentSubject));

when(postCommentSubject.supports(any())).thenReturn(true);
when(postCommentSubject.get(eq("fake-post"))).thenReturn(Mono.just(post()));

when(userService.getUserOrGhost(any()))
.thenReturn(Mono.just(ghostUser()));
when(userService.getUserOrGhost("A-owner"))
.thenReturn(Mono.just(createUser("A-owner")));
// when(userService.getUserOrGhost("A-owner"))
// .thenReturn(Mono.just(createUser("A-owner")));
when(userService.getUserOrGhost("B-owner"))
.thenReturn(Mono.just(createUser("B-owner")));

Expand Down Expand Up @@ -170,6 +151,12 @@ void listComment() {
@Test
@WithMockUser(username = "B-owner")
void create() throws JSONException {
var commentSetting = getCommentSetting();
when(environmentFetcher.fetchComment()).thenReturn(Mono.just(commentSetting));
when(roleService.contains(Set.of("USER"),
Set.of(AuthorityUtils.COMMENT_MANAGEMENT_ROLE_NAME)))
.thenReturn(Mono.just(false));

CommentRequest commentRequest = new CommentRequest();
commentRequest.setRaw("fake-raw");
commentRequest.setContent("fake-content");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
Expand Down Expand Up @@ -56,7 +56,7 @@ private List<Reply> createReplies(int size) {
@Autowired
private SchemeManager schemeManager;

@SpyBean
@MockitoSpyBean
private ReactiveExtensionClient reactiveClient;

@Autowired
Expand All @@ -65,7 +65,7 @@ private List<Reply> createReplies(int size) {
@Autowired
private IndexerFactory indexerFactory;

@SpyBean
@MockitoSpyBean
private ReplyServiceImpl replyService;

Mono<Extension> deleteImmediately(Extension extension) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package run.halo.app.core.endpoint.console;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;

import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.reactor.ratelimiter.operator.RateLimiterOperator;
import java.time.Duration;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -39,47 +35,49 @@
@ExtendWith(SpringExtension.class)
@WithMockUser(username = "fake-user", password = "fake-password")
class EmailVerificationCodeTest {

WebTestClient webClient;

@Mock
ReactiveExtensionClient client;

@Mock
EmailVerificationService emailVerificationService;

@Mock
UserService userService;

@Mock
RateLimiterRegistry rateLimiterRegistry;

@InjectMocks
UserEndpoint endpoint;

@BeforeEach
void setUp() {
var spyUserEndpoint = spy(endpoint);
webClient = WebTestClient.bindToRouterFunction(endpoint.endpoint())
.apply(springSecurity())
.build();
}

@Test
void sendEmailVerificationCode() {
var config = RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofSeconds(10))
.limitForPeriod(1)
.build();
var sendCodeRateLimiter = RateLimiterRegistry.of(config)
.rateLimiter("send-email-verification-code-fake-user:[email protected]");
doReturn(RateLimiterOperator.of(sendCodeRateLimiter)).when(spyUserEndpoint)
.sendEmailVerificationCodeRateLimiter(eq("fake-user"), eq("[email protected]"));

var verifyEmailRateLimiter = RateLimiterRegistry.of(config)
.rateLimiter("verify-email-fake-user");
doReturn(RateLimiterOperator.of(verifyEmailRateLimiter)).when(spyUserEndpoint)
.verificationEmailRateLimiter(eq("fake-user"));
when(rateLimiterRegistry.rateLimiter(
"send-email-verification-code-fake-user:[email protected]",
"send-email-verification-code")
).thenReturn(sendCodeRateLimiter);

webClient = WebTestClient.bindToRouterFunction(spyUserEndpoint.endpoint()).build()
.mutateWith(csrf());
}

@Test
void sendEmailVerificationCode() {
var user = new User();
user.setMetadata(new Metadata());
user.getMetadata().setName("fake-user");
user.setSpec(new User.UserSpec());
user.getSpec().setEmail("[email protected]");
when(client.get(eq(User.class), eq("fake-user"))).thenReturn(Mono.just(user));
when(emailVerificationService.sendVerificationCode(anyString(), anyString()))
.thenReturn(Mono.empty());
webClient.post()
Expand All @@ -100,6 +98,16 @@ void sendEmailVerificationCode() {

@Test
void verifyEmail() {
var config = RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofSeconds(10))
.limitForPeriod(1)
.build();

var verifyEmailRateLimiter = RateLimiterRegistry.of(config)
.rateLimiter("verify-email-fake-user");
when(rateLimiterRegistry.rateLimiter("verify-email-fake-user", "verify-email"))
.thenReturn(verifyEmailRateLimiter);

when(emailVerificationService.verify(anyString(), anyString()))
.thenReturn(Mono.empty());
when(userService.confirmPassword(anyString(), anyString()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand All @@ -37,7 +37,7 @@ public class UserEndpointIntegrationTest {
@Autowired
ReactiveExtensionClient client;

@MockBean
@MockitoBean
RoleService roleService;

@BeforeEach
Expand Down
Loading

0 comments on commit 86b95cc

Please sign in to comment.