Port converter, security, MCP and CDI-infra tests off Spring to Quarkus

This commit is contained in:
Anthony Stirling
2026-06-14 23:59:37 +01:00
parent a7373d0ff2
commit ccf2b88094
27 changed files with 1745 additions and 1813 deletions
@@ -1,16 +1,20 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.boot.ApplicationArguments;
@Disabled("TODO: Migration required - Spring Boot test framework not available in Quarkus")
/**
* MIGRATION (Spring -> Quarkus): {@code AppArgsCapture} replaced the Spring {@code
* ApplicationRunner.run(ApplicationArguments)} hook with a CDI {@code @Observes StartupEvent}
* observer reading a {@code @CommandLineArguments String[]} field. The tests drive that observer
* directly: the {@code args} field and {@code onStart} method are package-private, so they are set
* and invoked without a running CDI container (the {@code StartupEvent} payload is unused).
*/
class AppArgsCaptureTest {
private AppArgsCapture capture;
@@ -22,31 +26,27 @@ class AppArgsCaptureTest {
}
@Test
void run_withArgs_capturesArgs() {
ApplicationArguments args = mock(ApplicationArguments.class);
when(args.getSourceArgs()).thenReturn(new String[] {"--server.port=8080", "--debug"});
capture.run(args);
void onStart_withArgs_capturesArgs() {
capture.args = new String[] {"--server.port=8080", "--debug"};
capture.onStart(null);
assertEquals(List.of("--server.port=8080", "--debug"), AppArgsCapture.APP_ARGS.get());
}
@Test
void run_withNoArgs_capturesEmptyList() {
ApplicationArguments args = mock(ApplicationArguments.class);
when(args.getSourceArgs()).thenReturn(new String[] {});
capture.run(args);
void onStart_withNoArgs_capturesEmptyList() {
capture.args = new String[] {};
capture.onStart(null);
assertEquals(List.of(), AppArgsCapture.APP_ARGS.get());
}
@Test
void run_calledTwice_overwritesPreviousArgs() {
ApplicationArguments args1 = mock(ApplicationArguments.class);
when(args1.getSourceArgs()).thenReturn(new String[] {"--first"});
capture.run(args1);
void onStart_calledTwice_overwritesPreviousArgs() {
capture.args = new String[] {"--first"};
capture.onStart(null);
assertEquals(List.of("--first"), AppArgsCapture.APP_ARGS.get());
ApplicationArguments args2 = mock(ApplicationArguments.class);
when(args2.getSourceArgs()).thenReturn(new String[] {"--second", "--third"});
capture.run(args2);
capture.args = new String[] {"--second", "--third"};
capture.onStart(null);
assertEquals(List.of("--second", "--third"), AppArgsCapture.APP_ARGS.get());
}
@@ -1,110 +1,142 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.mockito.MockedStatic;
@Disabled("TODO: Migration required - Spring Boot test framework not available in Quarkus")
import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.InjectableInstance;
import jakarta.enterprise.inject.literal.NamedLiteral;
/**
* MIGRATION (Spring -> Quarkus): {@code ApplicationContextProvider} now resolves beans through
* the Arc CDI container ({@code Arc.container().select(...)}) instead of a Spring {@code
* ApplicationContext}. Tests drive it by mocking the static {@code Arc.container()} entry point;
* the "no container" state (a non-{@code @QuarkusTest} unit test) is simulated by stubbing {@code
* Arc.container()} to {@code null}, and "bean not found" by an unresolvable {@link
* InjectableInstance}. The Spring-only {@code setApplicationContext(...)} mutator was removed, so
* the former context-swap test no longer applies.
*
* <p>Every collaborator mock is fully built into a local before it is handed to {@code thenReturn},
* so a helper's own stubbing never nests inside an in-progress {@code when(...)} (which would trip
* {@code UnfinishedStubbingException}).
*/
class ApplicationContextProviderTest {
private ApplicationContextProvider provider;
@BeforeEach
void setUp() {
provider = new ApplicationContextProvider();
// Reset to null state
provider.setApplicationContext(null);
@SuppressWarnings("unchecked")
private static <T> InjectableInstance<T> resolvable(T bean) {
InjectableInstance<T> instance = mock(InjectableInstance.class);
when(instance.isResolvable()).thenReturn(true);
when(instance.get()).thenReturn(bean);
return instance;
}
@AfterEach
void tearDown() {
// Clean up static state
provider.setApplicationContext(null);
@SuppressWarnings("unchecked")
private static <T> InjectableInstance<T> unresolvable() {
InjectableInstance<T> instance = mock(InjectableInstance.class);
when(instance.isResolvable()).thenReturn(false);
return instance;
}
private static <T> ArcContainer containerSelecting(
Class<T> type, InjectableInstance<T> instance) {
ArcContainer container = mock(ArcContainer.class);
when(container.select(type)).thenReturn(instance);
return container;
}
private static <T> ArcContainer containerSelectingNamed(
Class<T> type, String name, InjectableInstance<T> instance) {
ArcContainer container = mock(ArcContainer.class);
when(container.select(type, NamedLiteral.of(name))).thenReturn(instance);
return container;
}
@Test
void getBean_byClass_whenNoContext_returnsNull() {
provider.setApplicationContext(null);
assertNull(ApplicationContextProvider.getBean(String.class));
void getBean_byClass_whenNoContainer_returnsNull() {
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(null);
assertNull(ApplicationContextProvider.getBean(String.class));
}
}
@Test
void getBean_byClass_whenBeanExists_returnsBean() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean(String.class)).thenReturn("hello");
provider.setApplicationContext(ctx);
assertEquals("hello", ApplicationContextProvider.getBean(String.class));
ArcContainer container = containerSelecting(String.class, resolvable("hello"));
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertEquals("hello", ApplicationContextProvider.getBean(String.class));
}
}
@Test
void getBean_byClass_whenBeanNotFound_returnsNull() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean(String.class)).thenThrow(new NoSuchBeanDefinitionException(""));
provider.setApplicationContext(ctx);
assertNull(ApplicationContextProvider.getBean(String.class));
ArcContainer container = containerSelecting(String.class, unresolvable());
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertNull(ApplicationContextProvider.getBean(String.class));
}
}
@Test
void getBean_byNameAndClass_whenNoContext_returnsNull() {
provider.setApplicationContext(null);
assertNull(ApplicationContextProvider.getBean("myBean", String.class));
void getBean_byNameAndClass_whenNoContainer_returnsNull() {
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(null);
assertNull(ApplicationContextProvider.getBean("myBean", String.class));
}
}
@Test
void getBean_byNameAndClass_whenBeanExists_returnsBean() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean("myBean", String.class)).thenReturn("world");
provider.setApplicationContext(ctx);
assertEquals("world", ApplicationContextProvider.getBean("myBean", String.class));
ArcContainer container =
containerSelectingNamed(String.class, "myBean", resolvable("world"));
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertEquals("world", ApplicationContextProvider.getBean("myBean", String.class));
}
}
@Test
void getBean_byNameAndClass_whenBeanNotFound_returnsNull() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean("missing", String.class)).thenThrow(new NoSuchBeanDefinitionException(""));
provider.setApplicationContext(ctx);
assertNull(ApplicationContextProvider.getBean("missing", String.class));
ArcContainer container = containerSelectingNamed(String.class, "missing", unresolvable());
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertNull(ApplicationContextProvider.getBean("missing", String.class));
}
}
@Test
void containsBean_whenNoContext_returnsFalse() {
provider.setApplicationContext(null);
assertFalse(ApplicationContextProvider.containsBean(String.class));
void containsBean_whenNoContainer_returnsFalse() {
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(null);
assertFalse(ApplicationContextProvider.containsBean(String.class));
}
}
@Test
void containsBean_whenBeanExists_returnsTrue() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean(String.class)).thenReturn("exists");
provider.setApplicationContext(ctx);
assertTrue(ApplicationContextProvider.containsBean(String.class));
ArcContainer container = containerSelecting(String.class, resolvable("exists"));
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertTrue(ApplicationContextProvider.containsBean(String.class));
}
}
@Test
void containsBean_whenBeanNotFound_returnsFalse() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean(Integer.class)).thenThrow(new NoSuchBeanDefinitionException(""));
provider.setApplicationContext(ctx);
assertFalse(ApplicationContextProvider.containsBean(Integer.class));
}
@Test
void setApplicationContext_updatesStaticContext() {
ApplicationContext ctx = mock(ApplicationContext.class);
when(ctx.getBean(String.class)).thenReturn("test");
provider.setApplicationContext(ctx);
assertEquals("test", ApplicationContextProvider.getBean(String.class));
// Now set a different context
ApplicationContext ctx2 = mock(ApplicationContext.class);
when(ctx2.getBean(String.class)).thenReturn("updated");
provider.setApplicationContext(ctx2);
assertEquals("updated", ApplicationContextProvider.getBean(String.class));
ArcContainer container = containerSelecting(Integer.class, unresolvable());
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertFalse(ApplicationContextProvider.containsBean(Integer.class));
}
}
}
@@ -1,79 +1,108 @@
package stirling.software.common.util;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.mockito.MockedStatic;
@Disabled("TODO: Migration required - Spring Boot test framework not available in Quarkus")
import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
import io.quarkus.arc.InjectableInstance;
/**
* MIGRATION (Spring -&gt; Quarkus): {@code SpringContextHolder} now resolves beans through the Arc
* CDI container ({@code Arc.container().select(...)} / {@code isRunning()}) instead of a Spring
* {@code ApplicationContext}. Tests drive it by mocking the static {@code Arc.container()} entry
* point. The Spring-only {@code setApplicationContext(...)} mutator was removed, so "container not
* initialized" is now expressed as {@code Arc.container() == null} (or a non-running container),
* and "bean not found" as an unresolvable {@link InjectableInstance}.
*
* <p>Every collaborator mock is fully built into a local before it is handed to {@code thenReturn},
* so a helper's own stubbing never nests inside an in-progress {@code when(...)} (which would trip
* {@code UnfinishedStubbingException}).
*/
class SpringContextHolderTest {
private ApplicationContext mockApplicationContext;
private SpringContextHolder contextHolder;
@SuppressWarnings("unchecked")
private static <T> InjectableInstance<T> resolvable(T bean) {
InjectableInstance<T> instance = mock(InjectableInstance.class);
when(instance.isResolvable()).thenReturn(true);
when(instance.get()).thenReturn(bean);
return instance;
}
@BeforeEach
void setUp() {
mockApplicationContext = mock(ApplicationContext.class);
contextHolder = new SpringContextHolder();
@SuppressWarnings("unchecked")
private static <T> InjectableInstance<T> unresolvable() {
InjectableInstance<T> instance = mock(InjectableInstance.class);
when(instance.isResolvable()).thenReturn(false);
return instance;
}
private static ArcContainer runningContainer() {
ArcContainer container = mock(ArcContainer.class);
when(container.isRunning()).thenReturn(true);
return container;
}
private static <T> ArcContainer runningContainerSelecting(
Class<T> type, InjectableInstance<T> instance) {
ArcContainer container = mock(ArcContainer.class);
when(container.isRunning()).thenReturn(true);
when(container.select(type)).thenReturn(instance);
return container;
}
@Test
void testSetApplicationContext() {
// Act
contextHolder.setApplicationContext(mockApplicationContext);
// Assert
assertTrue(SpringContextHolder.isInitialized());
void isInitialized_whenContainerRunning_returnsTrue() {
ArcContainer container = runningContainer();
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertTrue(SpringContextHolder.isInitialized());
}
}
@Test
void testGetBean_ByType() {
// Arrange
contextHolder.setApplicationContext(mockApplicationContext);
void isInitialized_whenNoContainer_returnsFalse() {
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(null);
assertFalse(SpringContextHolder.isInitialized());
}
}
@Test
void getBean_byType_whenBeanExists_returnsBean() {
TestBean expectedBean = new TestBean();
when(mockApplicationContext.getBean(TestBean.class)).thenReturn(expectedBean);
// Act
TestBean result = SpringContextHolder.getBean(TestBean.class);
// Assert
assertSame(expectedBean, result);
verify(mockApplicationContext).getBean(TestBean.class);
ArcContainer container =
runningContainerSelecting(TestBean.class, resolvable(expectedBean));
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertSame(expectedBean, SpringContextHolder.getBean(TestBean.class));
}
}
@Test
void testGetBean_ApplicationContextNotSet() {
// Don't set application context
// Act
TestBean result = SpringContextHolder.getBean(TestBean.class);
// Assert
assertNull(result);
void getBean_byType_whenContainerNotInitialized_returnsNull() {
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(null);
assertNull(SpringContextHolder.getBean(TestBean.class));
}
}
@Test
void testGetBean_BeanNotFound() {
// Arrange
contextHolder.setApplicationContext(mockApplicationContext);
when(mockApplicationContext.getBean(TestBean.class)).thenThrow(new MyBeansException());
// Act
TestBean result = SpringContextHolder.getBean(TestBean.class);
// Assert
assertNull(result);
void getBean_byType_whenBeanNotResolvable_returnsNull() {
ArcContainer container = runningContainerSelecting(TestBean.class, unresolvable());
try (MockedStatic<Arc> arc = mockStatic(Arc.class)) {
arc.when(Arc::container).thenReturn(container);
assertNull(SpringContextHolder.getBean(TestBean.class));
}
}
// Simple test class
private static class TestBean {}
private static class MyBeansException extends org.springframework.beans.BeansException {
public MyBeansException() {
super("Bean not found");
}
}
}