Add boot4-migration module: one Boot 3.5.16 service migrated to 4.1.2, with the real compile, start-up, silent and test failures captured at each step

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b4VQVEJWetTT1dYzyJ
This commit is contained in:
2026-10-29 05:57:26 +00:00
co-authored by Claude Sonnet 5.5
parent fd0cf9b527
commit 85074ed51a
45 changed files with 1021 additions and 0 deletions
@@ -0,0 +1,24 @@
package com.ankurm.migration;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
/** Prints the status of a Basic-authenticated POST without a CSRF token (to compare 3.5 with 4.1). */
@SpringBootTest(properties = "spring.security.user.password=pw")
@AutoConfigureMockMvc
class CsrfProbeTest {
@Autowired MockMvc mvc;
@Test
void postWithoutCsrfToken() throws Exception {
int status = mvc.perform(post("/anything").with(httpBasic("user", "pw"))).andReturn().getResponse().getStatus();
System.out.println("CSRFPROBE status=" + status);
}
}
@@ -0,0 +1,27 @@
package com.ankurm.migration;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
@SpringBootTest
@AutoConfigureMockMvc
class GreetingControllerTest {
@Autowired MockMvc mvc;
@MockitoBean GreetingService service;
@Test
void greetingUsesService() throws Exception {
given(service.title(7)).willReturn("mocked");
mvc.perform(get("/greetings/7")).andExpect(status().isOk()).andExpect(jsonPath("$.title").value("mocked"));
}
}
@@ -0,0 +1,22 @@
package com.ankurm.migration;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
/** Boot 4 fix: Mockito's own extension initialises @Mock fields. */
@SpringBootTest
@ExtendWith(MockitoExtension.class)
class MockFieldTest {
@Mock Runnable task;
@Test
void mockFieldIsInitialised() {
assertNotNull(task, "@Mock field was never initialised");
}
}
@@ -0,0 +1,50 @@
package com.ankurm.migration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.web.servlet.MockMvc;
/** Pins the runtime behaviour the "breaks at runtime" checklist is about, so a regression fails the build. */
@SpringBootTest
@AutoConfigureMockMvc
class RuntimeFactsTest {
@Autowired MockMvc mvc;
@Autowired JdbcTemplate jdbc;
@Test
void flywayMigrationRan() {
assertThat(jdbc.queryForObject("select count(*) from greeting", Integer.class)).isEqualTo(3);
}
@Test
void aspectIntercepts() throws Exception {
mvc.perform(get("/greetings/1")).andExpect(status().isOk());
assertThat(TimingAspect.COUNT.get()).isPositive();
}
@Test
void restClientBuilderIsAutoConfigured() throws Exception {
mvc.perform(get("/gateway")).andExpect(status().isOk());
}
@Test
void metricsEndpointExists() throws Exception {
mvc.perform(get("/actuator/metrics").with(user("u")))
.andExpect(status().isOk());
}
@Test
void serializerIsTheJacksonComponent() throws Exception {
mvc.perform(get("/greetings/2")).andExpect(content().json("{\"id\":2,\"title\":\"Hello #2\"}"));
}
}