From 0013e347b5b2c3074e366bcb099a9124399301a0 Mon Sep 17 00:00:00 2001 From: jayanth343 Date: Fri, 6 Feb 2026 08:13:31 +0000 Subject: [PATCH] Add unit tests for controllers and services in Portfolio Management System - Created tests for PortfolioManagementSystemApplication, DashboardController, PmsController, PortfolioController, StockDataController, TransactionController, and WalletController. - Implemented service tests for DashboardService, PmsService, TransactionService, and WalletService. - Added mockito extensions for inline mocking. - Ensured coverage for various scenarios including success and failure cases across all tests. --- logs/pms-application.log | 1954 +++++++++++++++++ .../src/pages/AssetDetails/AssetDetails.jsx | 6 +- reactpotfolio/src/pages/Home/Home.jsx | 2 +- .../org/hsbc/exception/ErrorResponse.java | 62 + .../exception/GlobalExceptionHandler.java | 64 + .../InsufficientBalanceException.java | 7 + .../exception/ResourceNotFoundException.java | 7 + .../hsbc/controller/PmsControllerTest.java | 59 +- .../controller/PortfolioControllerTest.java | 160 ++ .../controller/StockDataControllerTest.java | 424 ++-- .../hsbc/controller/WalletControllerTest.java | 27 +- .../java/org/hsbc/entity/PmsEntityTest.java | 83 + .../hsbc/entity/TransactionEntityTest.java | 64 + .../org/hsbc/entity/WalletEntityTest.java | 40 + .../hsbc/exception/ExceptionClassesTest.java | 77 + .../exception/GlobalExceptionHandlerTest.java | 96 + .../org/hsbc/service/PmsServiceimpTest.java | 68 + .../hsbc/service/WalletServiceimplTest.java | 5 +- ...folioManagementSystemApplicationTests.java | 13 + .../controller/DashboardControllerTest.java | 56 + .../hsbc/controller/PmsControllerTest.java | 144 ++ .../controller/PortfolioControllerTest.java | 160 ++ .../controller/StockDataControllerTest.java | 197 ++ .../controller/TransactionControllerTest.java | 92 + .../hsbc/controller/WalletControllerTest.java | 71 + .../hsbc/service/DashboardServiceTest.java | 57 + .../org/hsbc/service/PmsServiceimpTest.java | 183 ++ .../service/TransactionServiceimpTest.java | 151 ++ .../hsbc/service/WalletServiceimplTest.java | 92 + .../org.mockito.plugins.MockMaker | 1 + 30 files changed, 4221 insertions(+), 201 deletions(-) create mode 100644 src/main/java/org/hsbc/exception/ErrorResponse.java create mode 100644 src/main/java/org/hsbc/exception/GlobalExceptionHandler.java create mode 100644 src/main/java/org/hsbc/exception/InsufficientBalanceException.java create mode 100644 src/main/java/org/hsbc/exception/ResourceNotFoundException.java create mode 100644 src/test/java/org/hsbc/controller/PortfolioControllerTest.java create mode 100644 src/test/java/org/hsbc/entity/PmsEntityTest.java create mode 100644 src/test/java/org/hsbc/entity/TransactionEntityTest.java create mode 100644 src/test/java/org/hsbc/entity/WalletEntityTest.java create mode 100644 src/test/java/org/hsbc/exception/ExceptionClassesTest.java create mode 100644 src/test/java/org/hsbc/exception/GlobalExceptionHandlerTest.java create mode 100644 src/testbk/java/org/hsbc/PortfolioManagementSystemApplicationTests.java create mode 100644 src/testbk/java/org/hsbc/controller/DashboardControllerTest.java create mode 100644 src/testbk/java/org/hsbc/controller/PmsControllerTest.java create mode 100644 src/testbk/java/org/hsbc/controller/PortfolioControllerTest.java create mode 100644 src/testbk/java/org/hsbc/controller/StockDataControllerTest.java create mode 100644 src/testbk/java/org/hsbc/controller/TransactionControllerTest.java create mode 100644 src/testbk/java/org/hsbc/controller/WalletControllerTest.java create mode 100644 src/testbk/java/org/hsbc/service/DashboardServiceTest.java create mode 100644 src/testbk/java/org/hsbc/service/PmsServiceimpTest.java create mode 100644 src/testbk/java/org/hsbc/service/TransactionServiceimpTest.java create mode 100644 src/testbk/java/org/hsbc/service/WalletServiceimplTest.java create mode 100644 src/testbk/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/logs/pms-application.log b/logs/pms-application.log index 8affc1f..f5edb34 100644 --- a/logs/pms-application.log +++ b/logs/pms-application.log @@ -710,3 +710,1957 @@ java.lang.IllegalArgumentException: Invalid character found in method name [0x05 2026-02-06 06:32:13 INFO o.h.controller.StockDataController - Stock analysis request for: GC=F (inPortfolio=true, buyPrice=4840.113567839196) 2026-02-06 06:32:13 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/GC=F/analysis?inPortfolio=true&buyPrice=4840.113567839196 2026-02-06 06:32:16 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: GC=F +2026-02-06 07:21:19 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 21.0.9 with PID 11936 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:21:19 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:21:19 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:21:22 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:21:22 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:21:22 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms +2026-02-06 07:21:22 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 3.39 seconds (process running for 5.293) +2026-02-06 07:21:43 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 21.0.9 with PID 13564 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:21:43 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:21:43 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:21:46 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:21:46 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:21:46 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms +2026-02-06 07:21:46 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 3.136 seconds (process running for 4.564) +2026-02-06 07:25:07 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 21.0.9 with PID 740 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:25:07 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:25:07 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:25:10 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:25:10 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:25:10 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 2 ms +2026-02-06 07:25:10 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 3.567 seconds (process running for 7.22) +2026-02-06 07:28:47 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 21.0.9 with PID 16884 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:28:47 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:28:47 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:28:50 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:28:50 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:28:50 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 2 ms +2026-02-06 07:28:50 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 3.654 seconds (process running for 5.451) +2026-02-06 07:31:15 INFO o.h.c.PortfolioControllerTest - Starting PortfolioControllerTest using Java 21.0.9 with PID 17044 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:31:15 DEBUG o.h.c.PortfolioControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:31:15 INFO o.h.c.PortfolioControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:31:17 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:31:17 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:31:17 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms +2026-02-06 07:31:17 INFO o.h.c.PortfolioControllerTest - Started PortfolioControllerTest in 3.306 seconds (process running for 4.961) +2026-02-06 07:38:43 INFO o.h.c.StockDataControllerTest - Starting StockDataControllerTest using Java 21.0.9 with PID 8092 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:38:43 DEBUG o.h.c.StockDataControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:38:43 INFO o.h.c.StockDataControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:38:44 INFO o.h.controller.StockDataController - StockDataController initialized +2026-02-06 07:38:44 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:44 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:44 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms +2026-02-06 07:38:44 INFO o.h.c.StockDataControllerTest - Started StockDataControllerTest in 2.2 seconds (process running for 11.237) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Portfolio performers analysis request received +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Request body: {} +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/portfolio/performers +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error analyzing portfolio performers: 400 BAD_REQUEST +org.springframework.web.client.HttpClientErrorException: 400 BAD_REQUEST + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:536) + at org.hsbc.controller.StockDataController.getPortfolioPerformers(StockDataController.java:259) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetPortfolioPerformers_BadRequest(StockDataControllerTest.java:198) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for stock: AAPL +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/AAPL +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Successfully fetched stock data for: AAPL +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for mutual fund: VFIAX +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/mutual-funds/VFIAX +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Successfully fetched mutual fund data for: VFIAX +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for crypto: UNKNOWN +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/UNKNOWN +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error fetching crypto data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getCrypto(StockDataController.java:71) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetCrypto_NotFound(StockDataControllerTest.java:77) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Stock analysis request for: AAPL (inPortfolio=true, buyPrice=null) +2026-02-06 07:38:45 WARN o.h.controller.StockDataController - buyPrice missing for stock analysis: AAPL +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for history: UNKNOWN with period: 1MO, interval: null +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/UNKNOWN?period=1MO +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error fetching history for UNKNOWN (1MO, null): 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getHistory(StockDataController.java:166) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetHistory_NotFound(StockDataControllerTest.java:137) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for commodity: UNKNOWN +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/commodities/UNKNOWN +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error fetching commodity data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getCommodity(StockDataController.java:129) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetCommodity_NotFound(StockDataControllerTest.java:117) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Search request received with query: +2026-02-06 07:38:45 WARN o.h.controller.StockDataController - Empty search query received +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for news: AAPL +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/news/AAPL +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Successfully fetched news for: AAPL +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Portfolio recommendations request received +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Request body: [{"symbol":"AAPL"}] +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/portfolio/recommendations +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Portfolio recommendations generated successfully +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Health check request received +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Health check: Flask API is healthy +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for commodity: GC=F +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/commodities/GC=F +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Successfully fetched commodity data for: GC=F +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for history: AAPL with period: 1MO, interval: 1d +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AAPL?period=1MO&interval=1d +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Successfully fetched history for: AAPL (1MO, 1d) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for crypto: BTC +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/BTC +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Successfully fetched crypto data for: BTC +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for mutual fund: UNKNOWN +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/mutual-funds/UNKNOWN +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error fetching mutual fund data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getMutualFund(StockDataController.java:100) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetMutualFund_NotFound(StockDataControllerTest.java:97) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Portfolio performers analysis request received +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Request body: [{"symbol":"AAPL","buyPrice":100}] +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/portfolio/performers +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Portfolio performers analysis completed successfully +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Health check request received +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Health check failed: Flask API is not reachable - Connection refused +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for stock: UNKNOWN +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/UNKNOWN +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error fetching stock data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getStock(StockDataController.java:42) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetStock_NotFound(StockDataControllerTest.java:56) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Request received for news: UNKNOWN +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/news/UNKNOWN +2026-02-06 07:38:45 ERROR o.h.controller.StockDataController - Error fetching news for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getNews(StockDataController.java:195) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetNews_NotFound(StockDataControllerTest.java:157) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Stock analysis request for: AAPL (inPortfolio=true, buyPrice=150.0) +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/AAPL/analysis?inPortfolio=true&buyPrice=150.0 +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: AAPL +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Search request received with query: Apple +2026-02-06 07:38:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=Apple +2026-02-06 07:38:45 INFO o.h.controller.StockDataController - Search completed successfully for query: Apple +2026-02-06 07:38:45 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:38:45 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:38:45 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:38:45 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:45 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:38:46 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:46 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:46 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:38:46 INFO o.s.t.c.s.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [org.hsbc.controller.PmsControllerTest]: PmsControllerTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2026-02-06 07:38:46 INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.hsbc.PortfolioManagementSystemApplication for test class org.hsbc.controller.PmsControllerTest +2026-02-06 07:38:46 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 21.0.9 with PID 8092 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:38:46 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:38:46 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:38:46 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:46 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:46 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:38:46 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 0.462 seconds (process running for 12.89) +2026-02-06 07:38:46 INFO o.s.t.c.s.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [org.hsbc.controller.PortfolioControllerTest]: PortfolioControllerTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2026-02-06 07:38:46 INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.hsbc.PortfolioManagementSystemApplication for test class org.hsbc.controller.PortfolioControllerTest +2026-02-06 07:38:46 INFO o.h.c.PortfolioControllerTest - Starting PortfolioControllerTest using Java 21.0.9 with PID 8092 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:38:46 DEBUG o.h.c.PortfolioControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:38:46 INFO o.h.c.PortfolioControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:38:46 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:38:46 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:38:46 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms +2026-02-06 07:38:46 INFO o.h.c.PortfolioControllerTest - Started PortfolioControllerTest in 0.343 seconds (process running for 13.37) +2026-02-06 07:46:59 INFO o.h.c.StockDataControllerTest - Starting StockDataControllerTest using Java 21.0.9 with PID 10204 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:46:59 DEBUG o.h.c.StockDataControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:46:59 INFO o.h.c.StockDataControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:47:00 INFO o.h.controller.StockDataController - StockDataController initialized +2026-02-06 07:47:00 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:00 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:00 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 2 ms +2026-02-06 07:47:00 INFO o.h.c.StockDataControllerTest - Started StockDataControllerTest in 2.328 seconds (process running for 12.05) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Portfolio performers analysis request received +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Request body: {} +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/portfolio/performers +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error analyzing portfolio performers: 400 BAD_REQUEST +org.springframework.web.client.HttpClientErrorException: 400 BAD_REQUEST + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:536) + at org.hsbc.controller.StockDataController.getPortfolioPerformers(StockDataController.java:259) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetPortfolioPerformers_BadRequest(StockDataControllerTest.java:198) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for stock: AAPL +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/AAPL +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Successfully fetched stock data for: AAPL +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for mutual fund: VFIAX +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/mutual-funds/VFIAX +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Successfully fetched mutual fund data for: VFIAX +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for crypto: UNKNOWN +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/UNKNOWN +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error fetching crypto data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getCrypto(StockDataController.java:71) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetCrypto_NotFound(StockDataControllerTest.java:77) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Stock analysis request for: AAPL (inPortfolio=true, buyPrice=null) +2026-02-06 07:47:01 WARN o.h.controller.StockDataController - buyPrice missing for stock analysis: AAPL +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for history: UNKNOWN with period: 1MO, interval: null +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/UNKNOWN?period=1MO +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error fetching history for UNKNOWN (1MO, null): 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getHistory(StockDataController.java:166) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetHistory_NotFound(StockDataControllerTest.java:137) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for commodity: UNKNOWN +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/commodities/UNKNOWN +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error fetching commodity data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getCommodity(StockDataController.java:129) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetCommodity_NotFound(StockDataControllerTest.java:117) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Search request received with query: +2026-02-06 07:47:01 WARN o.h.controller.StockDataController - Empty search query received +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for news: AAPL +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/news/AAPL +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Successfully fetched news for: AAPL +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Portfolio recommendations request received +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Request body: [{"symbol":"AAPL"}] +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/portfolio/recommendations +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Portfolio recommendations generated successfully +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Health check request received +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Health check: Flask API is healthy +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for commodity: GC=F +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/commodities/GC=F +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Successfully fetched commodity data for: GC=F +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for history: AAPL with period: 1MO, interval: 1d +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AAPL?period=1MO&interval=1d +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Successfully fetched history for: AAPL (1MO, 1d) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for crypto: BTC +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/BTC +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Successfully fetched crypto data for: BTC +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for mutual fund: UNKNOWN +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/mutual-funds/UNKNOWN +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error fetching mutual fund data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getMutualFund(StockDataController.java:100) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetMutualFund_NotFound(StockDataControllerTest.java:97) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Portfolio performers analysis request received +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Request body: [{"symbol":"AAPL","buyPrice":100}] +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/portfolio/performers +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Portfolio performers analysis completed successfully +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Health check request received +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Health check failed: Flask API is not reachable - Connection refused +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for stock: UNKNOWN +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/UNKNOWN +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error fetching stock data for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getStock(StockDataController.java:42) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetStock_NotFound(StockDataControllerTest.java:56) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:01 INFO o.h.controller.StockDataController - Request received for news: UNKNOWN +2026-02-06 07:47:01 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/news/UNKNOWN +2026-02-06 07:47:01 ERROR o.h.controller.StockDataController - Error fetching news for UNKNOWN: 404 NOT_FOUND +org.springframework.web.client.HttpClientErrorException: 404 NOT_FOUND + at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:429) + at org.hsbc.controller.StockDataController.getNews(StockDataController.java:195) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:925) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:830) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) + at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) + at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) + at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:165) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.test.web.servlet.setup.MockMvcFilterDecorator.doFilter(MockMvcFilterDecorator.java:151) + at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:132) + at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:201) + at org.hsbc.controller.StockDataControllerTest.testGetNews_NotFound(StockDataControllerTest.java:157) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:728) + at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) + at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147) + at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:218) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:214) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:139) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:63) + at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:66) + at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) + at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) + at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) + at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) + at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) +2026-02-06 07:47:02 INFO o.h.controller.StockDataController - Stock analysis request for: AAPL (inPortfolio=true, buyPrice=150.0) +2026-02-06 07:47:02 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/AAPL/analysis?inPortfolio=true&buyPrice=150.0 +2026-02-06 07:47:02 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: AAPL +2026-02-06 07:47:02 INFO o.h.controller.StockDataController - Search request received with query: Apple +2026-02-06 07:47:02 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=Apple +2026-02-06 07:47:02 INFO o.h.controller.StockDataController - Search completed successfully for query: Apple +2026-02-06 07:47:02 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms +2026-02-06 07:47:02 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:47:02 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:47:02 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:47:02 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:02 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:47:02 INFO o.s.t.c.s.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [org.hsbc.controller.PmsControllerTest]: PmsControllerTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2026-02-06 07:47:02 INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.hsbc.PortfolioManagementSystemApplication for test class org.hsbc.controller.PmsControllerTest +2026-02-06 07:47:02 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 21.0.9 with PID 10204 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:47:02 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:47:02 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:47:03 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:03 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:03 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:47:03 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 0.645 seconds (process running for 14.111) +2026-02-06 07:47:03 INFO o.s.t.c.s.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [org.hsbc.controller.PortfolioControllerTest]: PortfolioControllerTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration. +2026-02-06 07:47:03 INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.hsbc.PortfolioManagementSystemApplication for test class org.hsbc.controller.PortfolioControllerTest +2026-02-06 07:47:03 INFO o.h.c.PortfolioControllerTest - Starting PortfolioControllerTest using Java 21.0.9 with PID 10204 (started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 07:47:03 DEBUG o.h.c.PortfolioControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 07:47:03 INFO o.h.c.PortfolioControllerTest - No active profile set, falling back to 1 default profile: "default" +2026-02-06 07:47:03 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet '' +2026-02-06 07:47:03 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet '' +2026-02-06 07:47:03 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms +2026-02-06 07:47:03 INFO o.h.c.PortfolioControllerTest - Started PortfolioControllerTest in 0.438 seconds (process running for 14.806) +2026-02-06 07:48:19 INFO o.h.controller.StockDataController - Request received for history: ITC.NS with period: 1mo, interval: 1h +2026-02-06 07:48:19 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/ITC.NS?period=1MO&interval=1h +2026-02-06 07:48:19 INFO o.h.controller.StockDataController - Successfully fetched history for: ITC.NS (1mo, 1h) +2026-02-06 07:48:19 INFO o.h.controller.StockDataController - Request received for history: ITC.NS with period: 1mo, interval: 1h +2026-02-06 07:48:19 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/ITC.NS?period=1MO&interval=1h +2026-02-06 07:48:19 INFO o.h.controller.StockDataController - Successfully fetched history for: ITC.NS (1mo, 1h) +2026-02-06 07:48:55 INFO o.h.controller.StockDataController - Search request received with query: State Street SPDR S +2026-02-06 07:48:55 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=State Street SPDR S +2026-02-06 07:48:56 INFO o.h.controller.StockDataController - Search completed successfully for query: State Street SPDR S +2026-02-06 07:48:56 INFO o.h.controller.StockDataController - Search request received with query: State Street SPDR S +2026-02-06 07:48:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=State Street SPDR S +2026-02-06 07:48:56 INFO o.h.controller.StockDataController - Search completed successfully for query: State Street SPDR S +2026-02-06 07:49:10 INFO o.h.controller.StockDataController - Search request received with query: State Street SPDR S +2026-02-06 07:49:10 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=State Street SPDR S +2026-02-06 07:49:10 INFO o.h.controller.StockDataController - Search completed successfully for query: State Street SPDR S +2026-02-06 07:49:13 INFO o.h.controller.StockDataController - Request received for stock: LVLN +2026-02-06 07:49:13 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/LVLN +2026-02-06 07:49:13 INFO o.h.controller.StockDataController - Successfully fetched stock data for: LVLN +2026-02-06 07:49:13 INFO o.h.controller.StockDataController - Request received for stock: LVLN +2026-02-06 07:49:13 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/LVLN +2026-02-06 07:49:14 INFO o.h.controller.StockDataController - Request received for history: LVLN with period: 1mo, interval: 1h +2026-02-06 07:49:14 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/LVLN?period=1MO&interval=1h +2026-02-06 07:49:14 INFO o.h.controller.StockDataController - Successfully fetched history for: LVLN (1mo, 1h) +2026-02-06 07:49:14 INFO o.h.controller.StockDataController - Request received for history: LVLN with period: 1mo, interval: 1h +2026-02-06 07:49:14 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/LVLN?period=1MO&interval=1h +2026-02-06 07:49:14 INFO o.h.controller.StockDataController - Successfully fetched history for: LVLN (1mo, 1h) +2026-02-06 07:49:14 INFO o.h.controller.StockDataController - Successfully fetched stock data for: LVLN +2026-02-06 07:49:18 INFO o.h.controller.StockDataController - Request received for stock: SPY +2026-02-06 07:49:18 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/SPY +2026-02-06 07:49:18 INFO o.h.controller.StockDataController - Successfully fetched stock data for: SPY +2026-02-06 07:49:18 INFO o.h.controller.StockDataController - Request received for stock: SPY +2026-02-06 07:49:18 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/SPY +2026-02-06 07:49:18 INFO o.h.controller.StockDataController - Request received for history: SPY with period: 1mo, interval: 1h +2026-02-06 07:49:18 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/SPY?period=1MO&interval=1h +2026-02-06 07:49:18 INFO o.h.controller.StockDataController - Successfully fetched history for: SPY (1mo, 1h) +2026-02-06 07:49:18 INFO o.h.controller.StockDataController - Request received for history: SPY with period: 1mo, interval: 1h +2026-02-06 07:49:18 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/SPY?period=1MO&interval=1h +2026-02-06 07:49:19 INFO o.h.controller.StockDataController - Successfully fetched history for: SPY (1mo, 1h) +2026-02-06 07:49:19 INFO o.h.controller.StockDataController - Successfully fetched stock data for: SPY +2026-02-06 07:49:36 INFO o.h.controller.StockDataController - Stock analysis request for: SPY (inPortfolio=false, buyPrice=null) +2026-02-06 07:49:36 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/SPY/analysis?inPortfolio=false +2026-02-06 07:49:39 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: SPY +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Request received for stock: SPY +2026-02-06 07:52:32 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/SPY +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Successfully fetched stock data for: SPY +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Request received for stock: SPY +2026-02-06 07:52:32 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/SPY +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Request received for history: SPY with period: 1mo, interval: 1h +2026-02-06 07:52:32 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/SPY?period=1MO&interval=1h +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Successfully fetched history for: SPY (1mo, 1h) +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Request received for history: SPY with period: 1mo, interval: 1h +2026-02-06 07:52:32 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/SPY?period=1MO&interval=1h +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Successfully fetched history for: SPY (1mo, 1h) +2026-02-06 07:52:32 INFO o.h.controller.StockDataController - Successfully fetched stock data for: SPY +2026-02-06 07:52:44 INFO o.h.controller.StockDataController - Request received for history: 0P0000XVFU.BO with period: 1mo, interval: 1h +2026-02-06 07:52:44 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/0P0000XVFU.BO?period=1MO&interval=1h +2026-02-06 07:52:44 INFO o.h.controller.StockDataController - Successfully fetched history for: 0P0000XVFU.BO (1mo, 1h) +2026-02-06 07:52:44 INFO o.h.controller.StockDataController - Request received for history: 0P0000XVFU.BO with period: 1mo, interval: 1h +2026-02-06 07:52:44 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/0P0000XVFU.BO?period=1MO&interval=1h +2026-02-06 07:52:44 INFO o.h.controller.StockDataController - Successfully fetched history for: 0P0000XVFU.BO (1mo, 1h) +2026-02-06 07:52:48 INFO o.h.controller.StockDataController - Stock analysis request for: 0P0000XVFU.BO (inPortfolio=true, buyPrice=59.49) +2026-02-06 07:52:48 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/0P0000XVFU.BO/analysis?inPortfolio=true&buyPrice=59.49 +2026-02-06 07:52:48 WARN o.h.controller.StockDataController - Unable to analyze stock: 0P0000XVFU.BO +2026-02-06 07:52:50 INFO o.h.controller.StockDataController - Request received for history: 0P0000XVFU.BO with period: 1mo, interval: 1h +2026-02-06 07:52:50 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/0P0000XVFU.BO?period=1MO&interval=1h +2026-02-06 07:52:50 INFO o.h.controller.StockDataController - Successfully fetched history for: 0P0000XVFU.BO (1mo, 1h) +2026-02-06 07:52:51 INFO o.h.controller.StockDataController - Request received for history: 0P0000XVFU.BO with period: 1mo, interval: 1h +2026-02-06 07:52:51 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/0P0000XVFU.BO?period=1MO&interval=1h +2026-02-06 07:52:51 INFO o.h.controller.StockDataController - Successfully fetched history for: 0P0000XVFU.BO (1mo, 1h) +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Request received for stock: 0P0000XVFU.BO +2026-02-06 07:52:54 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/0P0000XVFU.BO +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Successfully fetched stock data for: 0P0000XVFU.BO +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Request received for stock: 0P0000XVFU.BO +2026-02-06 07:52:54 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/0P0000XVFU.BO +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Request received for history: 0P0000XVFU.BO with period: 1mo, interval: 1h +2026-02-06 07:52:54 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/0P0000XVFU.BO?period=1MO&interval=1h +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Successfully fetched history for: 0P0000XVFU.BO (1mo, 1h) +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Request received for history: 0P0000XVFU.BO with period: 1mo, interval: 1h +2026-02-06 07:52:54 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/0P0000XVFU.BO?period=1MO&interval=1h +2026-02-06 07:52:54 INFO o.h.controller.StockDataController - Successfully fetched history for: 0P0000XVFU.BO (1mo, 1h) +2026-02-06 07:52:55 INFO o.h.controller.StockDataController - Successfully fetched stock data for: 0P0000XVFU.BO +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Request received for stock: POWERINDIA.NS +2026-02-06 07:55:55 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/POWERINDIA.NS +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Successfully fetched stock data for: POWERINDIA.NS +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Request received for stock: POWERINDIA.NS +2026-02-06 07:55:55 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/POWERINDIA.NS +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Request received for history: POWERINDIA.NS with period: 1mo, interval: 1h +2026-02-06 07:55:55 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/POWERINDIA.NS?period=1MO&interval=1h +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Successfully fetched history for: POWERINDIA.NS (1mo, 1h) +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Request received for history: POWERINDIA.NS with period: 1mo, interval: 1h +2026-02-06 07:55:55 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/POWERINDIA.NS?period=1MO&interval=1h +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Successfully fetched stock data for: POWERINDIA.NS +2026-02-06 07:55:55 INFO o.h.controller.StockDataController - Successfully fetched history for: POWERINDIA.NS (1mo, 1h) +2026-02-06 07:56:07 INFO o.h.controller.StockDataController - Stock analysis request for: POWERINDIA.NS (inPortfolio=false, buyPrice=null) +2026-02-06 07:56:07 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/POWERINDIA.NS/analysis?inPortfolio=false +2026-02-06 07:56:08 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: POWERINDIA.NS +2026-02-06 07:59:32 INFO o.h.controller.StockDataController - Search request received with query: palantir +2026-02-06 07:59:32 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=palantir +2026-02-06 07:59:32 INFO o.h.controller.StockDataController - Search completed successfully for query: palantir +2026-02-06 07:59:32 INFO o.h.controller.StockDataController - Search request received with query: palantir +2026-02-06 07:59:32 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=palantir +2026-02-06 07:59:32 INFO o.h.controller.StockDataController - Search completed successfully for query: palantir +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Request received for stock: PLTR +2026-02-06 07:59:34 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/PLTR +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Successfully fetched stock data for: PLTR +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Request received for stock: PLTR +2026-02-06 07:59:34 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/PLTR +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Request received for history: PLTR with period: 1mo, interval: 1h +2026-02-06 07:59:34 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/PLTR?period=1MO&interval=1h +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Successfully fetched history for: PLTR (1mo, 1h) +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Request received for history: PLTR with period: 1mo, interval: 1h +2026-02-06 07:59:34 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/PLTR?period=1MO&interval=1h +2026-02-06 07:59:34 INFO o.h.controller.StockDataController - Successfully fetched history for: PLTR (1mo, 1h) +2026-02-06 07:59:35 INFO o.h.controller.StockDataController - Successfully fetched stock data for: PLTR +2026-02-06 07:59:44 INFO o.h.controller.StockDataController - Stock analysis request for: PLTR (inPortfolio=false, buyPrice=null) +2026-02-06 07:59:44 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/PLTR/analysis?inPortfolio=false +2026-02-06 07:59:47 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: PLTR +2026-02-06 08:00:02 INFO o.h.controller.StockDataController - Search request received with query: openai +2026-02-06 08:00:02 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=openai +2026-02-06 08:00:05 INFO o.h.controller.StockDataController - Search completed successfully for query: openai +2026-02-06 08:00:05 INFO o.h.controller.StockDataController - Search request received with query: openai +2026-02-06 08:00:05 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=openai +2026-02-06 08:00:05 INFO o.h.controller.StockDataController - Search completed successfully for query: openai +2026-02-06 08:00:27 INFO o.h.controller.StockDataController - Search request received with query: anthropic +2026-02-06 08:00:27 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=anthropic +2026-02-06 08:00:28 INFO o.h.controller.StockDataController - Search completed successfully for query: anthropic +2026-02-06 08:00:35 INFO o.h.controller.StockDataController - Search request received with query: hp +2026-02-06 08:00:35 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=hp +2026-02-06 08:00:35 INFO o.h.controller.StockDataController - Search completed successfully for query: hp +2026-02-06 08:00:39 INFO o.h.controller.StockDataController - Request received for stock: HPQ +2026-02-06 08:00:39 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/HPQ +2026-02-06 08:00:39 INFO o.h.controller.StockDataController - Successfully fetched stock data for: HPQ +2026-02-06 08:00:39 INFO o.h.controller.StockDataController - Request received for stock: HPQ +2026-02-06 08:00:39 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/HPQ +2026-02-06 08:00:39 INFO o.h.controller.StockDataController - Request received for history: HPQ with period: 1mo, interval: 1h +2026-02-06 08:00:40 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/HPQ?period=1MO&interval=1h +2026-02-06 08:00:40 INFO o.h.controller.StockDataController - Successfully fetched history for: HPQ (1mo, 1h) +2026-02-06 08:00:40 INFO o.h.controller.StockDataController - Request received for history: HPQ with period: 1mo, interval: 1h +2026-02-06 08:00:40 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/HPQ?period=1MO&interval=1h +2026-02-06 08:00:40 INFO o.h.controller.StockDataController - Successfully fetched history for: HPQ (1mo, 1h) +2026-02-06 08:00:40 INFO o.h.controller.StockDataController - Successfully fetched stock data for: HPQ +2026-02-06 08:00:50 INFO o.h.controller.StockDataController - Stock analysis request for: HPQ (inPortfolio=false, buyPrice=null) +2026-02-06 08:00:50 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stock/HPQ/analysis?inPortfolio=false +2026-02-06 08:00:53 INFO o.h.controller.StockDataController - Stock analysis completed successfully for: HPQ +2026-02-06 08:01:37 INFO o.h.controller.StockDataController - Search request received with query: bitcoin +2026-02-06 08:01:37 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=bitcoin +2026-02-06 08:01:38 INFO o.h.controller.StockDataController - Search completed successfully for query: bitcoin +2026-02-06 08:01:38 INFO o.h.controller.StockDataController - Search request received with query: bitcoin +2026-02-06 08:01:38 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=bitcoin +2026-02-06 08:01:39 INFO o.h.controller.StockDataController - Search completed successfully for query: bitcoin +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Request received for crypto: BTC-USD +2026-02-06 08:01:49 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/BTC-USD +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Successfully fetched crypto data for: BTC-USD +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Request received for crypto: BTC-USD +2026-02-06 08:01:49 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/BTC-USD +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Request received for history: BTC-USD with period: 1mo, interval: 1h +2026-02-06 08:01:49 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/BTC-USD?period=1MO&interval=1h +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Successfully fetched history for: BTC-USD (1mo, 1h) +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Request received for history: BTC-USD with period: 1mo, interval: 1h +2026-02-06 08:01:49 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/BTC-USD?period=1MO&interval=1h +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Successfully fetched crypto data for: BTC-USD +2026-02-06 08:01:49 INFO o.h.controller.StockDataController - Successfully fetched history for: BTC-USD (1mo, 1h) +2026-02-06 08:02:20 INFO o.h.controller.StockDataController - Search request received with query: mutual fund +2026-02-06 08:02:20 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=mutual fund +2026-02-06 08:02:21 INFO o.h.controller.StockDataController - Search completed successfully for query: mutual fund +2026-02-06 08:02:21 INFO o.h.controller.StockDataController - Search request received with query: mutual fund +2026-02-06 08:02:21 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=mutual fund +2026-02-06 08:02:21 INFO o.h.controller.StockDataController - Search completed successfully for query: mutual fund +2026-02-06 08:02:28 INFO o.h.controller.StockDataController - Request received for stock: AMRMX +2026-02-06 08:02:28 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/AMRMX +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Successfully fetched stock data for: AMRMX +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Request received for stock: AMRMX +2026-02-06 08:02:29 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/AMRMX +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Request received for history: AMRMX with period: 1mo, interval: 1h +2026-02-06 08:02:29 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AMRMX?period=1MO&interval=1h +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Successfully fetched history for: AMRMX (1mo, 1h) +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Request received for history: AMRMX with period: 1mo, interval: 1h +2026-02-06 08:02:29 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AMRMX?period=1MO&interval=1h +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Successfully fetched history for: AMRMX (1mo, 1h) +2026-02-06 08:02:29 INFO o.h.controller.StockDataController - Successfully fetched stock data for: AMRMX +2026-02-06 08:06:06 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default' +2026-02-06 08:06:06 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... +2026-02-06 08:06:06 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. +2026-02-06 08:06:28 INFO o.h.PortfolioManagementSystemApplication - Starting PortfolioManagementSystemApplication using Java 21.0.9 with PID 16484 (C:\Users\Administrator\JavaLearning\PortfolioManagementSystem\target\classes started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 08:06:28 DEBUG o.h.PortfolioManagementSystemApplication - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 08:06:28 INFO o.h.PortfolioManagementSystemApplication - No active profile set, falling back to 1 default profile: "default" +2026-02-06 08:06:29 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-02-06 08:06:29 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 69 ms. Found 3 JPA repository interfaces. +2026-02-06 08:06:29 INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http) +2026-02-06 08:06:29 INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2026-02-06 08:06:29 INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.19] +2026-02-06 08:06:29 INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2026-02-06 08:06:29 INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1885 ms +2026-02-06 08:06:30 INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default] +2026-02-06 08:06:30 INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.4.4.Final +2026-02-06 08:06:30 INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled +2026-02-06 08:06:30 INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer +2026-02-06 08:06:31 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... +2026-02-06 08:06:31 INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@4f402027 +2026-02-06 08:06:31 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. +2026-02-06 08:06:33 INFO o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2026-02-06 08:06:33 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default' +2026-02-06 08:06:33 INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used. +2026-02-06 08:06:34 INFO o.h.controller.StockDataController - StockDataController initialized +2026-02-06 08:06:34 WARN o.s.b.a.o.j.JpaBaseConfiguration$JpaWebConfiguration - spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2026-02-06 08:06:35 INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '' +2026-02-06 08:06:35 INFO o.h.PortfolioManagementSystemApplication - Started PortfolioManagementSystemApplication in 7.942 seconds (process running for 8.403) +2026-02-06 08:06:56 INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2026-02-06 08:06:56 INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2026-02-06 08:06:56 INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms +2026-02-06 08:07:44 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default' +2026-02-06 08:07:44 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... +2026-02-06 08:07:44 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. +2026-02-06 08:07:58 INFO o.h.PortfolioManagementSystemApplication - Starting PortfolioManagementSystemApplication using Java 21.0.9 with PID 13356 (C:\Users\Administrator\JavaLearning\PortfolioManagementSystem\target\classes started by Administrator in C:\Users\Administrator\JavaLearning\PortfolioManagementSystem) +2026-02-06 08:07:58 DEBUG o.h.PortfolioManagementSystemApplication - Running with Spring Boot v3.2.4, Spring v6.1.5 +2026-02-06 08:07:58 INFO o.h.PortfolioManagementSystemApplication - No active profile set, falling back to 1 default profile: "default" +2026-02-06 08:07:59 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-02-06 08:07:59 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 68 ms. Found 3 JPA repository interfaces. +2026-02-06 08:08:00 INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http) +2026-02-06 08:08:00 INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2026-02-06 08:08:00 INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.19] +2026-02-06 08:08:00 INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2026-02-06 08:08:00 INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1618 ms +2026-02-06 08:08:00 INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default] +2026-02-06 08:08:00 INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.4.4.Final +2026-02-06 08:08:00 INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled +2026-02-06 08:08:00 INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer +2026-02-06 08:08:00 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... +2026-02-06 08:08:01 INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@7c226095 +2026-02-06 08:08:01 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. +2026-02-06 08:08:02 INFO o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) +2026-02-06 08:08:02 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default' +2026-02-06 08:08:02 INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used. +2026-02-06 08:08:03 INFO o.h.controller.StockDataController - StockDataController initialized +2026-02-06 08:08:03 WARN o.s.b.a.o.j.JpaBaseConfiguration$JpaWebConfiguration - spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning +2026-02-06 08:08:04 INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '' +2026-02-06 08:08:04 INFO o.h.PortfolioManagementSystemApplication - Started PortfolioManagementSystemApplication in 6.023 seconds (process running for 6.413) +2026-02-06 08:08:14 INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2026-02-06 08:08:14 INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2026-02-06 08:08:14 INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms +2026-02-06 08:08:23 INFO o.h.controller.StockDataController - Request received for history: AMRMX with period: 1mo, interval: 1h +2026-02-06 08:08:23 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AMRMX?period=1MO&interval=1h +2026-02-06 08:08:23 INFO o.h.controller.StockDataController - Successfully fetched history for: AMRMX (1mo, 1h) +2026-02-06 08:08:23 INFO o.h.controller.StockDataController - Request received for history: AMRMX with period: 1mo, interval: 1h +2026-02-06 08:08:23 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AMRMX?period=1MO&interval=1h +2026-02-06 08:08:23 INFO o.h.controller.StockDataController - Successfully fetched history for: AMRMX (1mo, 1h) +2026-02-06 08:08:41 INFO o.h.controller.StockDataController - Request received for history: GC=F with period: 1mo, interval: 1h +2026-02-06 08:08:41 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/GC=F?period=1MO&interval=1h +2026-02-06 08:08:41 INFO o.h.controller.StockDataController - Successfully fetched history for: GC=F (1mo, 1h) +2026-02-06 08:08:41 INFO o.h.controller.StockDataController - Request received for history: GC=F with period: 1mo, interval: 1h +2026-02-06 08:08:41 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/GC=F?period=1MO&interval=1h +2026-02-06 08:08:41 INFO o.h.controller.StockDataController - Successfully fetched history for: GC=F (1mo, 1h) +2026-02-06 08:08:57 INFO o.h.controller.StockDataController - Request received for history: BTC-USD with period: 1mo, interval: 1h +2026-02-06 08:08:57 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/BTC-USD?period=1MO&interval=1h +2026-02-06 08:08:57 INFO o.h.controller.StockDataController - Successfully fetched history for: BTC-USD (1mo, 1h) +2026-02-06 08:08:57 INFO o.h.controller.StockDataController - Request received for history: BTC-USD with period: 1mo, interval: 1h +2026-02-06 08:08:57 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/BTC-USD?period=1MO&interval=1h +2026-02-06 08:08:57 INFO o.h.controller.StockDataController - Successfully fetched history for: BTC-USD (1mo, 1h) +2026-02-06 08:09:10 INFO o.h.controller.StockDataController - Request received for history: POWERINDIA.NS with period: 1mo, interval: 1h +2026-02-06 08:09:10 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/POWERINDIA.NS?period=1MO&interval=1h +2026-02-06 08:09:10 INFO o.h.controller.StockDataController - Successfully fetched history for: POWERINDIA.NS (1mo, 1h) +2026-02-06 08:09:10 INFO o.h.controller.StockDataController - Request received for history: POWERINDIA.NS with period: 1mo, interval: 1h +2026-02-06 08:09:10 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/POWERINDIA.NS?period=1MO&interval=1h +2026-02-06 08:09:10 INFO o.h.controller.StockDataController - Successfully fetched history for: POWERINDIA.NS (1mo, 1h) +2026-02-06 08:09:45 INFO o.h.controller.StockDataController - Request received for history: BTC-USD with period: 1mo, interval: 1h +2026-02-06 08:09:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/BTC-USD?period=1MO&interval=1h +2026-02-06 08:09:45 INFO o.h.controller.StockDataController - Successfully fetched history for: BTC-USD (1mo, 1h) +2026-02-06 08:09:45 INFO o.h.controller.StockDataController - Request received for history: BTC-USD with period: 1mo, interval: 1h +2026-02-06 08:09:45 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/BTC-USD?period=1MO&interval=1h +2026-02-06 08:09:46 INFO o.h.controller.StockDataController - Successfully fetched history for: BTC-USD (1mo, 1h) +2026-02-06 08:12:40 INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 558 ms diff --git a/reactpotfolio/src/pages/AssetDetails/AssetDetails.jsx b/reactpotfolio/src/pages/AssetDetails/AssetDetails.jsx index ce55245..34f349d 100644 --- a/reactpotfolio/src/pages/AssetDetails/AssetDetails.jsx +++ b/reactpotfolio/src/pages/AssetDetails/AssetDetails.jsx @@ -494,7 +494,7 @@ const AssetDetails = () => { > - + {type?.toLowerCase() !== 'mutualfund' && } {type?.toLowerCase() !== 'mutualfund' && } @@ -672,7 +672,7 @@ const AssetDetails = () => { )} {/* Recommendations Tab */} - {tabValue === 2 && ( + {tabValue === 2 && type?.toLowerCase() !== 'mutualfund' && ( What Experts Think @@ -833,7 +833,7 @@ const AssetDetails = () => { )} {/* AI Analysis Tab */} - {tabValue === 3 && ( + {tabValue === 3 && type?.toLowerCase() !== 'mutualfund' && ( diff --git a/reactpotfolio/src/pages/Home/Home.jsx b/reactpotfolio/src/pages/Home/Home.jsx index 9657b91..f9339a6 100644 --- a/reactpotfolio/src/pages/Home/Home.jsx +++ b/reactpotfolio/src/pages/Home/Home.jsx @@ -208,7 +208,7 @@ const Home = () => { Portfolio Dashboard - Welcome back, {summary?.userName || 'User'} + Welcome back, User diff --git a/src/main/java/org/hsbc/exception/ErrorResponse.java b/src/main/java/org/hsbc/exception/ErrorResponse.java new file mode 100644 index 0000000..e84983f --- /dev/null +++ b/src/main/java/org/hsbc/exception/ErrorResponse.java @@ -0,0 +1,62 @@ +package org.hsbc.exception; + +import java.time.LocalDateTime; + +public class ErrorResponse { + private LocalDateTime timestamp; + private int status; + private String error; + private String message; + private String path; + + public ErrorResponse() { + } + + public ErrorResponse(int status, String error, String message, String path) { + this.timestamp = LocalDateTime.now(); + this.status = status; + this.error = error; + this.message = message; + this.path = path; + } + + public LocalDateTime getTimestamp() { + return timestamp; + } + + public void setTimestamp(LocalDateTime timestamp) { + this.timestamp = timestamp; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/src/main/java/org/hsbc/exception/GlobalExceptionHandler.java b/src/main/java/org/hsbc/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..e29fdd8 --- /dev/null +++ b/src/main/java/org/hsbc/exception/GlobalExceptionHandler.java @@ -0,0 +1,64 @@ +package org.hsbc.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFoundException(ResourceNotFoundException ex, + WebRequest request) { + ErrorResponse errorResponse = new ErrorResponse( + HttpStatus.NOT_FOUND.value(), + HttpStatus.NOT_FOUND.getReasonPhrase(), + ex.getMessage(), + request.getDescription(false).replace("uri=", "")); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(InsufficientBalanceException.class) + public ResponseEntity handleInsufficientBalanceException(InsufficientBalanceException ex, + WebRequest request) { + ErrorResponse errorResponse = new ErrorResponse( + HttpStatus.BAD_REQUEST.value(), + HttpStatus.BAD_REQUEST.getReasonPhrase(), + ex.getMessage(), + request.getDescription(false).replace("uri=", "")); + return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(InvalidPmsIdException.class) + public ResponseEntity handleInvalidPmsIdException(InvalidPmsIdException ex, WebRequest request) { + ErrorResponse errorResponse = new ErrorResponse( + HttpStatus.NOT_FOUND.value(), + HttpStatus.NOT_FOUND.getReasonPhrase(), + ex.getMessage(), + request.getDescription(false).replace("uri=", "")); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(InvalidTransactionIdException.class) + public ResponseEntity handleInvalidTransactionIdException(InvalidTransactionIdException ex, + WebRequest request) { + ErrorResponse errorResponse = new ErrorResponse( + HttpStatus.NOT_FOUND.value(), + HttpStatus.NOT_FOUND.getReasonPhrase(), + ex.getMessage(), + request.getDescription(false).replace("uri=", "")); + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGlobalException(Exception ex, WebRequest request) { + ErrorResponse errorResponse = new ErrorResponse( + HttpStatus.INTERNAL_SERVER_ERROR.value(), + HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), + ex.getMessage(), + request.getDescription(false).replace("uri=", "")); + return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/org/hsbc/exception/InsufficientBalanceException.java b/src/main/java/org/hsbc/exception/InsufficientBalanceException.java new file mode 100644 index 0000000..07d8db8 --- /dev/null +++ b/src/main/java/org/hsbc/exception/InsufficientBalanceException.java @@ -0,0 +1,7 @@ +package org.hsbc.exception; + +public class InsufficientBalanceException extends RuntimeException { + public InsufficientBalanceException(String message) { + super(message); + } +} diff --git a/src/main/java/org/hsbc/exception/ResourceNotFoundException.java b/src/main/java/org/hsbc/exception/ResourceNotFoundException.java new file mode 100644 index 0000000..3d35dca --- /dev/null +++ b/src/main/java/org/hsbc/exception/ResourceNotFoundException.java @@ -0,0 +1,7 @@ +package org.hsbc.exception; + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String message) { + super(message); + } +} diff --git a/src/test/java/org/hsbc/controller/PmsControllerTest.java b/src/test/java/org/hsbc/controller/PmsControllerTest.java index 3b6c522..5656b6f 100644 --- a/src/test/java/org/hsbc/controller/PmsControllerTest.java +++ b/src/test/java/org/hsbc/controller/PmsControllerTest.java @@ -38,9 +38,9 @@ void testAddAsset() throws Exception { when(service.addAsset(any(PmsEntity.class))).thenReturn(asset); - mockMvc.perform(post("/pms/add") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(asset))) + mockMvc.perform(post("/api/pms/add") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(asset))) .andExpect(status().isOk()) .andExpect(jsonPath("$.companyName").value("Apple")) .andExpect(jsonPath("$.quantity").value(10)); @@ -51,7 +51,7 @@ void testAddAsset() throws Exception { void testRemoveAsset() throws Exception { doNothing().when(service).removeAsset(1L); - mockMvc.perform(delete("/pms/remove/1")) + mockMvc.perform(delete("/api/pms/remove/1")) .andExpect(status().isOk()) .andExpect(content().string("Asset removed successfully")); } @@ -65,8 +65,8 @@ void testUpdateQuantity() throws Exception { when(service.updateQuantity(1L, 20)).thenReturn(updated); - mockMvc.perform(put("/pms/update-quantity/1") - .param("quantity", "20")) + mockMvc.perform(put("/api/pms/update-quantity/1") + .param("quantity", "20")) .andExpect(status().isOk()) .andExpect(jsonPath("$.quantity").value(20)); } @@ -76,17 +76,25 @@ void testUpdateQuantity() throws Exception { void testGetPL() throws Exception { when(service.calculatePL(1L)).thenReturn(200.0); - mockMvc.perform(get("/pms/pl/1")) + mockMvc.perform(get("/api/pms/pl/1")) .andExpect(status().isOk()) .andExpect(content().string("200.0")); } + @Test + void testGetPL_NotFound() throws Exception { + when(service.calculatePL(99L)).thenThrow(new org.hsbc.exception.InvalidPmsIdException("Not Found")); + + mockMvc.perform(get("/api/pms/pl/99")) + .andExpect(status().isNotFound()); + } + // 5️⃣ GET /pms/pl-percentage/{id} @Test void testGetPLPercentage() throws Exception { when(service.calculatePLPercentage(1L)).thenReturn(20.0); - mockMvc.perform(get("/pms/pl-percentage/1")) + mockMvc.perform(get("/api/pms/pl-percentage/1")) .andExpect(status().isOk()) .andExpect(content().string("20.0")); } @@ -96,8 +104,41 @@ void testGetPLPercentage() throws Exception { void testGetTotalValue() throws Exception { when(service.getTotalPortfolioValue()).thenReturn(1200.0); - mockMvc.perform(get("/pms/total-value")) + mockMvc.perform(get("/api/pms/total-value")) .andExpect(status().isOk()) .andExpect(content().string("1200.0")); } + + @Test + void testGetAssetById() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setId(1L); + when(service.getAssetById(1L)).thenReturn(asset); + + mockMvc.perform(get("/api/pms/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(1)); + } + + @Test + void testGetAssetById_NotFound() throws Exception { + when(service.getAssetById(99L)).thenThrow(new org.hsbc.exception.InvalidPmsIdException("Not Found")); + + mockMvc.perform(get("/api/pms/99")) + .andExpect(status().isNotFound()); + } + + @Test + void testUpdatePrice() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setSymbol("AAPL"); + asset.setCurrentPrice(150.0); + + when(service.updateCurrentPrice("AAPL", 150.0)).thenReturn(asset); + + mockMvc.perform(put("/api/pms/update-price/AAPL") + .param("price", "150.0")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.currentPrice").value(150.0)); + } } diff --git a/src/test/java/org/hsbc/controller/PortfolioControllerTest.java b/src/test/java/org/hsbc/controller/PortfolioControllerTest.java new file mode 100644 index 0000000..2651e07 --- /dev/null +++ b/src/test/java/org/hsbc/controller/PortfolioControllerTest.java @@ -0,0 +1,160 @@ +package org.hsbc.controller; + +import org.hsbc.entity.PmsEntity; +import org.hsbc.service.PmsService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(PortfolioController.class) +class PortfolioControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private PmsService pmsService; + + @Autowired + private PortfolioController portfolioController; + + private RestTemplate restTemplateMock; + + @BeforeEach + void setUp() { + restTemplateMock = mock(RestTemplate.class); + ReflectionTestUtils.setField(portfolioController, "restTemplate", restTemplateMock); + } + + @Test + void testGetPortfolioSummary() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setBuyPrice(100.0); + asset.setQuantity(10); // Invested: 1000 + asset.setCurrentPrice(120.0); // Current: 1200 + asset.setBuyingValue(1000.0); + + when(pmsService.getAllAssets()).thenReturn(Collections.singletonList(asset)); + + mockMvc.perform(get("/api/portfolio/summary")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.portfolioValue").value(1200.0)) + .andExpect(jsonPath("$.totalInvested").value(1000.0)) + .andExpect(jsonPath("$.totalGain").value(200.0)) + .andExpect(jsonPath("$.gainPercentage").value(20.0)); + } + + @Test + void testGetPortfolioPerformance() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setSymbol("AAPL"); + asset.setQuantity(10); + asset.setAssetType("Stocks"); + + when(pmsService.getAllAssets()).thenReturn(Collections.singletonList(asset)); + + String mockApiResponse = "{\"data\": [{\"time\": \"2023-01-01\", \"close\": 150.0}]}"; + when(restTemplateMock.getForObject(anyString(), eq(String.class))).thenReturn(mockApiResponse); + + mockMvc.perform(get("/api/portfolio/performance")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].date").value("2023-01-01")) + .andExpect(jsonPath("$[0].value").value(1500)); // 150 * 10 + } + + @Test + void testGetPortfolioPerformance_EmptyAssets() throws Exception { + when(pmsService.getAllAssets()).thenReturn(Collections.emptyList()); + + mockMvc.perform(get("/api/portfolio/performance")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(0))); + } + + @Test + void testGetAssetAllocation() throws Exception { + PmsEntity stock = new PmsEntity(); + stock.setAssetType("Stocks"); + stock.setCurrentPrice(100.0); + stock.setQuantity(10); // 1000 + + PmsEntity crypto = new PmsEntity(); + crypto.setAssetType("Crypto"); + crypto.setCurrentPrice(50.0); + crypto.setQuantity(20); // 1000 + + when(pmsService.getAllAssets()).thenReturn(Arrays.asList(stock, crypto)); + + mockMvc.perform(get("/api/portfolio/allocation")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(2))) + .andExpect(jsonPath("$[*].assetType", containsInAnyOrder("Stocks", "Crypto"))) + .andExpect(jsonPath("$[*].value", containsInAnyOrder(1000.0, 1000.0))); + } + + @Test + void testGetInvestmentBreakdown() throws Exception { + PmsEntity stock = new PmsEntity(); + stock.setAssetType("Stock"); // Should normalize to Stocks + stock.setBuyingValue(1000.0); + + when(pmsService.getAllAssets()).thenReturn(Collections.singletonList(stock)); + + mockMvc.perform(get("/api/portfolio/breakdown")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].type").value("Stocks")) + .andExpect(jsonPath("$[0].value").value(1000.0)); + } + + @Test + void testGetInvestmentBreakdown_Empty() throws Exception { + when(pmsService.getAllAssets()).thenReturn(Collections.emptyList()); + + mockMvc.perform(get("/api/portfolio/breakdown")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(4))); // Expects all 4 types with 0 + } + + @Test + void testGetPerformers() throws Exception { + PmsEntity winner = new PmsEntity(); + winner.setSymbol("WIN"); + winner.setBuyPrice(100.0); + winner.setBuyingValue(1000.00); // Set buying value explicit + winner.setCurrentPrice(200.0); + winner.setQuantity(10); + + PmsEntity loser = new PmsEntity(); + loser.setSymbol("LOSE"); + loser.setBuyPrice(100.0); + loser.setBuyingValue(1000.00); // Set buying value explicit + loser.setCurrentPrice(50.0); + loser.setQuantity(10); + + when(pmsService.getAllAssets()).thenReturn(Arrays.asList(winner, loser)); + + mockMvc.perform(get("/api/portfolio/performers")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.topPerformers[0].symbol").value("WIN")) + .andExpect(jsonPath("$.lowestPerformers[0].symbol").value("LOSE")); + } +} diff --git a/src/test/java/org/hsbc/controller/StockDataControllerTest.java b/src/test/java/org/hsbc/controller/StockDataControllerTest.java index 586f6dc..5b493c7 100644 --- a/src/test/java/org/hsbc/controller/StockDataControllerTest.java +++ b/src/test/java/org/hsbc/controller/StockDataControllerTest.java @@ -1,197 +1,255 @@ - package org.hsbc.controller; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; 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 static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; - -@ExtendWith(MockitoExtension.class) -public class StockDataControllerTest { - - private MockMvc mockMvc; - - @Mock - private RestTemplate restTemplate; - - @InjectMocks - private StockDataController stockDataController; - - private final String FLASK_URL = "http://localhost:5000"; - - @BeforeEach - void setUp() { - // 1. Inject the Flask URL value (simulating @Value) - ReflectionTestUtils.setField(stockDataController, "flaskApiUrl", FLASK_URL); - - // 2. Overwrite the hardcoded RestTemplate with our Mock using Reflection - // This is necessary because the controller does 'new RestTemplate()' in the constructor - ReflectionTestUtils.setField(stockDataController, "restTemplate", restTemplate); - - // 3. Build the standalone MockMvc context - mockMvc = MockMvcBuilders.standaloneSetup(stockDataController).build(); - } - - // ========================================== - // 1. GET Stock Tests - // ========================================== - - @Test - void getStock_Success() throws Exception { - String mockResponse = "{\"symbol\":\"AAPL\",\"price\":150.0}"; - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/stocks/AAPL"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/stocks/AAPL")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - @Test - void getStock_NotFound() throws Exception { - when(restTemplate.getForEntity(anyString(), eq(String.class))) - .thenThrow( HttpClientErrorException.NotFound.class); - - mockMvc.perform(get("/api/yfdata/stocks/UNKNOWN")) - .andExpect(status().isNotFound()) - .andExpect(jsonPath("$.error").value("Stock not found")); - } - - @Test - void getStock_ServerError() throws Exception { - when(restTemplate.getForEntity(anyString(), eq(String.class))) - .thenThrow(new RuntimeException("Flask down")); - - mockMvc.perform(get("/api/yfdata/stocks/AAPL")) - .andExpect(status().isInternalServerError()) - .andExpect(jsonPath("$.error").exists()); - } - - // ========================================== - // 2. GET Crypto Tests - // ========================================== - - @Test - void getCrypto_Success() throws Exception { - String mockResponse = "{\"symbol\":\"BTC\",\"price\":50000.0}"; - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/crypto/BTC"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/crypto/BTC")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - // ========================================== - // 3. GET Mutual Fund Tests - // ========================================== - - @Test - void getMutualFund_Success() throws Exception { - String mockResponse = "{\"symbol\":\"VFIAX\",\"nav\":400.0}"; - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/mutual-funds/VFIAX"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/mutual-funds/VFIAX")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - // ========================================== - // 4. GET Commodity Tests - // ========================================== - - @Test - void getCommodity_Success() throws Exception { - String mockResponse = "{\"symbol\":\"GC=F\",\"price\":1900.0}"; - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/commodities/GC=F"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/commodities/GC=F")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - // ========================================== - // 5. GET History Tests - // ========================================== - - @Test - void getHistory_DefaultPeriod() throws Exception { - String mockResponse = "{\"history\":[]}"; - // Verify default period is 1MO - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/history/AAPL?period=1MO"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/history/AAPL")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - @Test - void getHistory_CustomPeriod() throws Exception { - String mockResponse = "{\"history\":[]}"; - // Verify custom period 1Y - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/history/AAPL?period=1Y"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/history/AAPL").param("period", "1Y")) - .andExpect(status().isOk()); - } - - // ========================================== - // 6. GET News Tests - // ========================================== - - @Test - void getNews_Success() throws Exception { - String mockResponse = "[{\"title\":\"News 1\"}]"; - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/news/AAPL"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/news/AAPL")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - // ========================================== - // 7. GET Search Tests - // ========================================== - - @Test - void searchAssets_Success() throws Exception { - String mockResponse = "[{\"symbol\":\"AAPL\"}]"; - when(restTemplate.getForEntity(eq(FLASK_URL + "/api/search?q=Apple"), eq(String.class))) - .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); - - mockMvc.perform(get("/api/yfdata/search").param("q", "Apple")) - .andExpect(status().isOk()) - .andExpect(content().json(mockResponse)); - } - - @Test - void searchAssets_MissingQuery() throws Exception { - // The controller checks if q is null or empty manually - mockMvc.perform(get("/api/yfdata/search").param("q", "")) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.error").value("Query parameter 'q' is required")); - } -} - -// =========================== \ No newline at end of file +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(StockDataController.class) +class StockDataControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private StockDataController controller; + + private RestTemplate restTemplate; + + @BeforeEach + void setUp() { + restTemplate = mock(RestTemplate.class); + ReflectionTestUtils.setField(controller, "restTemplate", restTemplate); + ReflectionTestUtils.setField(controller, "flaskApiUrl", "http://localhost:5000"); + } + + @Test + void testGetStock_Success() throws Exception { + String json = "{\"symbol\":\"AAPL\",\"price\":150.0}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/stocks/AAPL")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetStock_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + mockMvc.perform(get("/api/yfdata/stocks/UNKNOWN")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.error").value("Stock not found")); + } + + @Test + void testGetCrypto_Success() throws Exception { + String json = "{\"symbol\":\"BTC\",\"price\":40000.0}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/crypto/BTC")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetCrypto_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + mockMvc.perform(get("/api/yfdata/crypto/UNKNOWN")) + .andExpect(status().isNotFound()); + } + + @Test + void testGetMutualFund_Success() throws Exception { + String json = "{\"symbol\":\"VFIAX\",\"nav\":400.0}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/mutual-funds/VFIAX")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetMutualFund_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + mockMvc.perform(get("/api/yfdata/mutual-funds/UNKNOWN")) + .andExpect(status().isNotFound()); + } + + @Test + void testGetCommodity_Success() throws Exception { + String json = "{\"symbol\":\"GC=F\",\"price\":1800.0}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/commodities/GC=F")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetCommodity_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + mockMvc.perform(get("/api/yfdata/commodities/UNKNOWN")) + .andExpect(status().isNotFound()); + } + + @Test + void testGetHistory_Success() throws Exception { + String json = "{\"date\":\"2023-01-01\",\"close\":150.0}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/history/AAPL?period=1MO&interval=1d")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetHistory_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + mockMvc.perform(get("/api/yfdata/history/UNKNOWN")) + .andExpect(status().isNotFound()); + } + + @Test + void testGetNews_Success() throws Exception { + String json = "[{\"title\":\"News 1\"}]"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/news/AAPL")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetNews_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + mockMvc.perform(get("/api/yfdata/news/UNKNOWN")) + .andExpect(status().isNotFound()); + } + + @Test + void testSearchAssets_Success() throws Exception { + String json = "[{\"symbol\":\"AAPL\"}]"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/search?q=Apple")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testSearchAssets_EmptyQuery() throws Exception { + mockMvc.perform(get("/api/yfdata/search?q=")) + .andExpect(status().isBadRequest()); + } + + @Test + void testGetPortfolioPerformers_Success() throws Exception { + String requestBody = "[{\"symbol\":\"AAPL\",\"buyPrice\":100}]"; + String responseBody = "{\"top\":[]}"; + + when(restTemplate.postForEntity(anyString(), any(), eq(String.class))) + .thenReturn(ResponseEntity.ok(responseBody)); + + mockMvc.perform(post("/api/yfdata/portfolio/performers") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andExpect(status().isOk()) + .andExpect(content().json(responseBody)); + } + + @Test + void testGetPortfolioPerformers_BadRequest() throws Exception { + when(restTemplate.postForEntity(anyString(), any(), eq(String.class))) + .thenThrow(new HttpClientErrorException(HttpStatus.BAD_REQUEST)); + + mockMvc.perform(post("/api/yfdata/portfolio/performers") + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isBadRequest()); + } + + @Test + void testGetPortfolioRecommendations_Success() throws Exception { + String requestBody = "[{\"symbol\":\"AAPL\"}]"; + String responseBody = "{\"recommendations\":[]}"; + + when(restTemplate.postForEntity(anyString(), any(), eq(String.class))) + .thenReturn(ResponseEntity.ok(responseBody)); + + mockMvc.perform(post("/api/yfdata/portfolio/recommendations") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andExpect(status().isOk()) + .andExpect(content().json(responseBody)); + } + + @Test + void testGetStockAnalysis_Success() throws Exception { + String json = "{\"sentiment\":\"Bullish\"}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/stock/AAPL/analysis?inPortfolio=true&buyPrice=150.0")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testGetStockAnalysis_MissingBuyPrice() throws Exception { + mockMvc.perform(get("/api/yfdata/stock/AAPL/analysis?inPortfolio=true")) + .andExpect(status().isBadRequest()); + } + + @Test + void testHealthCheck_Success() throws Exception { + String json = "{\"status\":\"healthy\"}"; + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenReturn(ResponseEntity.ok(json)); + + mockMvc.perform(get("/api/yfdata/health")) + .andExpect(status().isOk()) + .andExpect(content().json(json)); + } + + @Test + void testHealthCheck_Failure() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new RuntimeException("Connection refused")); + + mockMvc.perform(get("/api/yfdata/health")) + .andExpect(status().isServiceUnavailable()); + } +} \ No newline at end of file diff --git a/src/test/java/org/hsbc/controller/WalletControllerTest.java b/src/test/java/org/hsbc/controller/WalletControllerTest.java index 69da6bb..65929d8 100644 --- a/src/test/java/org/hsbc/controller/WalletControllerTest.java +++ b/src/test/java/org/hsbc/controller/WalletControllerTest.java @@ -1,5 +1,6 @@ package org.hsbc.controller; +import org.hsbc.entity.WalletEntity; import org.hsbc.service.WalletService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,6 +15,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 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; @ExtendWith(MockitoExtension.class) @@ -51,7 +53,7 @@ void testAddMoney() throws Exception { // Act & Assert // Note: controller expects @RequestParam, so we use .param("amount", ...) mockMvc.perform(post("/wallet/add") - .param("amount", "1000.0")) + .param("amount", "1000.0")) .andExpect(status().isOk()) .andExpect(content().string("6000.0")); } @@ -64,8 +66,29 @@ void testDeductMoney() throws Exception { // Act & Assert mockMvc.perform(post("/wallet/deduct") - .param("amount", "500.0")) + .param("amount", "500.0")) .andExpect(status().isOk()) .andExpect(content().string("4500.0")); } + + @Test + void testDeductMoney_InsufficientBalance() throws Exception { + when(service.deductMoney(10000.0)) + .thenThrow(new org.hsbc.exception.InsufficientBalanceException("Insufficient balance")); + + mockMvc.perform(post("/wallet/deduct") + .param("amount", "10000.0")) + .andExpect(status().isBadRequest()); + } + + @Test + void testGetWalletSummary() throws Exception { + WalletEntity wallet = new WalletEntity(); + wallet.setBalance(5000.0); + when(service.getWalletSummary()).thenReturn(wallet); + + mockMvc.perform(get("/wallet/summary")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.balance").value(5000.0)); + } } \ No newline at end of file diff --git a/src/test/java/org/hsbc/entity/PmsEntityTest.java b/src/test/java/org/hsbc/entity/PmsEntityTest.java new file mode 100644 index 0000000..e34e4a5 --- /dev/null +++ b/src/test/java/org/hsbc/entity/PmsEntityTest.java @@ -0,0 +1,83 @@ +package org.hsbc.entity; + +import org.junit.jupiter.api.Test; +import java.time.LocalDate; +import static org.junit.jupiter.api.Assertions.*; + +class PmsEntityTest { + + @Test + void testNoArgsConstructor() { + PmsEntity entity = new PmsEntity(); + assertNotNull(entity); + } + + @Test + void testAllArgsConstructor() { + LocalDate date = LocalDate.now(); + PmsEntity entity = new PmsEntity(1L, "Apple", "AAPL", 10, 100.0, 150.0, 1000.0, "USD", "NASDAQ", "Tech", + "Stock"); + entity.setPurchaseDate(date); + + assertEquals(1L, entity.getId()); + assertEquals("Apple", entity.getCompanyName()); + assertEquals("AAPL", entity.getSymbol()); + assertEquals(10, entity.getQuantity()); + assertEquals(100.0, entity.getBuyPrice()); + assertEquals(150.0, entity.getCurrentPrice()); + assertEquals(1000.0, entity.getBuyingValue()); + assertEquals("USD", entity.getCurrency()); + assertEquals("NASDAQ", entity.getExchange()); + assertEquals("Tech", entity.getIndustry()); + assertEquals("Stock", entity.getAssetType()); + assertEquals(date, entity.getPurchaseDate()); + } + + @Test + void testConstructorWithoutId() { + PmsEntity entity = new PmsEntity("Apple", "AAPL", 10, 100.0, 150.0, 1000.0, "USD", "NASDAQ", "Tech", "Stock"); + assertEquals("Apple", entity.getCompanyName()); + } + + @Test + void testSettersAndGetters() { + PmsEntity entity = new PmsEntity(); + LocalDate date = LocalDate.now(); + + entity.setId(1L); + entity.setCompanyName("Apple"); + entity.setSymbol("AAPL"); + entity.setQuantity(10); + entity.setBuyPrice(100.0); + entity.setCurrentPrice(150.0); + entity.setBuyingValue(1000.0); + entity.setCurrency("USD"); + entity.setExchange("NASDAQ"); + entity.setIndustry("Tech"); + entity.setAssetType("Stock"); + entity.setPurchaseDate(date); + + assertEquals(1L, entity.getId()); + assertEquals("Apple", entity.getCompanyName()); + assertEquals("AAPL", entity.getSymbol()); + assertEquals(10, entity.getQuantity()); + assertEquals(100.0, entity.getBuyPrice()); + assertEquals(150.0, entity.getCurrentPrice()); + assertEquals(1000.0, entity.getBuyingValue()); + assertEquals("USD", entity.getCurrency()); + assertEquals("NASDAQ", entity.getExchange()); + assertEquals("Tech", entity.getIndustry()); + assertEquals("Stock", entity.getAssetType()); + assertEquals(date, entity.getPurchaseDate()); + } + + @Test + void testToString() { + PmsEntity entity = new PmsEntity(); + entity.setId(1L); + entity.setSymbol("AAPL"); + String str = entity.toString(); + assertTrue(str.contains("id=1")); + assertTrue(str.contains("symbol='AAPL'")); + } +} diff --git a/src/test/java/org/hsbc/entity/TransactionEntityTest.java b/src/test/java/org/hsbc/entity/TransactionEntityTest.java new file mode 100644 index 0000000..b3f62d8 --- /dev/null +++ b/src/test/java/org/hsbc/entity/TransactionEntityTest.java @@ -0,0 +1,64 @@ +package org.hsbc.entity; + +import org.junit.jupiter.api.Test; +import java.time.LocalDateTime; +import static org.junit.jupiter.api.Assertions.*; + +class TransactionEntityTest { + + @Test + void testNoArgsConstructor() { + TransactionEntity entity = new TransactionEntity(); + assertNotNull(entity); + } + + @Test + void testAllArgsConstructor() { + LocalDateTime now = LocalDateTime.now(); + TransactionEntity entity = new TransactionEntity(1L, "AAPL", 10, 150.0, now, "BUY"); + + assertEquals(1L, entity.getTransactionId()); + assertEquals("AAPL", entity.getSymbol()); + assertEquals(10, entity.getQuantity()); + assertEquals(150.0, entity.getBuyPrice()); + assertEquals(now, entity.getTransactionDate()); + assertEquals("BUY", entity.getTransactionType()); + } + + @Test + void testConstructorWithoutId() { + LocalDateTime now = LocalDateTime.now(); + TransactionEntity entity = new TransactionEntity("AAPL", 10, 150.0, now, "BUY"); + assertEquals("AAPL", entity.getSymbol()); + } + + @Test + void testSettersAndGetters() { + TransactionEntity entity = new TransactionEntity(); + LocalDateTime now = LocalDateTime.now(); + + entity.setTransactionId(1L); + entity.setSymbol("AAPL"); + entity.setQuantity(10); + entity.setBuyPrice(150.0); + entity.setTransactionDate(now); + entity.setTransactionType("BUY"); + + assertEquals(1L, entity.getTransactionId()); + assertEquals("AAPL", entity.getSymbol()); + assertEquals(10, entity.getQuantity()); + assertEquals(150.0, entity.getBuyPrice()); + assertEquals(now, entity.getTransactionDate()); + assertEquals("BUY", entity.getTransactionType()); + } + + @Test + void testToString() { + TransactionEntity entity = new TransactionEntity(); + entity.setTransactionId(1L); + entity.setSymbol("AAPL"); + String str = entity.toString(); + assertTrue(str.contains("transactionId=1")); + assertTrue(str.contains("symbol='AAPL'")); + } +} diff --git a/src/test/java/org/hsbc/entity/WalletEntityTest.java b/src/test/java/org/hsbc/entity/WalletEntityTest.java new file mode 100644 index 0000000..0ae3d25 --- /dev/null +++ b/src/test/java/org/hsbc/entity/WalletEntityTest.java @@ -0,0 +1,40 @@ +package org.hsbc.entity; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class WalletEntityTest { + + @Test + void testNoArgsConstructor() { + WalletEntity entity = new WalletEntity(); + assertNotNull(entity); + } + + @Test + void testAllArgsConstructor() { + WalletEntity entity = new WalletEntity(1L, 5000.0); + assertEquals(1L, entity.getId()); + assertEquals(5000.0, entity.getBalance()); + } + + @Test + void testSettersAndGetters() { + WalletEntity entity = new WalletEntity(); + entity.setId(1L); + entity.setBalance(5000.0); + + assertEquals(1L, entity.getId()); + assertEquals(5000.0, entity.getBalance()); + } + + @Test + void testToString() { + WalletEntity entity = new WalletEntity(); + entity.setId(1L); + entity.setBalance(5000.0); + String str = entity.toString(); + assertTrue(str.contains("id=1")); + assertTrue(str.contains("balance=5000.0")); + } +} diff --git a/src/test/java/org/hsbc/exception/ExceptionClassesTest.java b/src/test/java/org/hsbc/exception/ExceptionClassesTest.java new file mode 100644 index 0000000..ea63d23 --- /dev/null +++ b/src/test/java/org/hsbc/exception/ExceptionClassesTest.java @@ -0,0 +1,77 @@ +package org.hsbc.exception; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class ExceptionClassesTest { + + @Test + void testResourceNotFoundException() { + ResourceNotFoundException ex = new ResourceNotFoundException("Not found"); + assertEquals("Not found", ex.getMessage()); + } + + @Test + void testInsufficientBalanceException() { + InsufficientBalanceException ex = new InsufficientBalanceException("Low balance"); + assertEquals("Low balance", ex.getMessage()); + } + + @Test + void testInvalidPmsIdException() { + InvalidPmsIdException ex1 = new InvalidPmsIdException(); + assertNull(ex1.getMessage()); + + InvalidPmsIdException ex2 = new InvalidPmsIdException("Invalid ID"); + assertEquals("Invalid ID", ex2.getMessage()); + + Throwable cause = new RuntimeException("Cause"); + InvalidPmsIdException ex3 = new InvalidPmsIdException(cause); + assertEquals(cause, ex3.getCause()); + + InvalidPmsIdException ex4 = new InvalidPmsIdException("Message", cause); + assertEquals("Message", ex4.getMessage()); + assertEquals(cause, ex4.getCause()); + + InvalidPmsIdException ex5 = new InvalidPmsIdException("Message", cause, true, true); + assertEquals("Message", ex5.getMessage()); + } + + @Test + void testInvalidTransactionIdException() { + InvalidTransactionIdException ex1 = new InvalidTransactionIdException(); + assertNull(ex1.getMessage()); + + InvalidTransactionIdException ex2 = new InvalidTransactionIdException("Invalid ID"); + assertEquals("Invalid ID", ex2.getMessage()); + + Throwable cause = new RuntimeException("Cause"); + InvalidTransactionIdException ex3 = new InvalidTransactionIdException(cause); + assertEquals(cause, ex3.getCause()); + + InvalidTransactionIdException ex4 = new InvalidTransactionIdException("Message", cause); + assertEquals("Message", ex4.getMessage()); + assertEquals(cause, ex4.getCause()); + + InvalidTransactionIdException ex5 = new InvalidTransactionIdException("Message", cause, true, true); + assertEquals("Message", ex5.getMessage()); + } + + @Test + void testErrorResponse() { + ErrorResponse er = new ErrorResponse(); + er.setStatus(404); + er.setError("Not Found"); + er.setMessage("Missing"); + er.setPath("/api/test"); + + assertEquals(404, er.getStatus()); + assertEquals("Not Found", er.getError()); + assertEquals("Missing", er.getMessage()); + assertEquals("/api/test", er.getPath()); + assertNotNull(er.getTimestamp()); // Default constructor sets timestamp now + + ErrorResponse er2 = new ErrorResponse(500, "Error", "Msg", "/path"); + assertEquals(500, er2.getStatus()); + } +} diff --git a/src/test/java/org/hsbc/exception/GlobalExceptionHandlerTest.java b/src/test/java/org/hsbc/exception/GlobalExceptionHandlerTest.java new file mode 100644 index 0000000..837bad9 --- /dev/null +++ b/src/test/java/org/hsbc/exception/GlobalExceptionHandlerTest.java @@ -0,0 +1,96 @@ +package org.hsbc.exception; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +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; + +@ExtendWith(MockitoExtension.class) +class GlobalExceptionHandlerTest { + + private MockMvc mockMvc; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(new TestController()) + .setControllerAdvice(new GlobalExceptionHandler()) + .build(); + } + + @Test + void testHandleResourceNotFoundException() throws Exception { + mockMvc.perform(get("/test/resource-not-found") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("Resource not found")); + } + + @Test + void testHandleInsufficientBalanceException() throws Exception { + mockMvc.perform(get("/test/insufficient-balance") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("Insufficient balance")); + } + + @Test + void testHandleInvalidPmsIdException() throws Exception { + mockMvc.perform(get("/test/invalid-pms-id") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("Invalid PMS ID")); + } + + @Test + void testHandleInvalidTransactionIdException() throws Exception { + mockMvc.perform(get("/test/invalid-transaction-id") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("Invalid Transaction ID")); + } + + @Test + void testHandleGlobalException() throws Exception { + mockMvc.perform(get("/test/global-exception") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.message").value("Internal error")); + } + + @RestController + static class TestController { + @GetMapping("/test/resource-not-found") + public void throwResourceNotFound() { + throw new ResourceNotFoundException("Resource not found"); + } + + @GetMapping("/test/insufficient-balance") + public void throwInsufficientBalance() { + throw new InsufficientBalanceException("Insufficient balance"); + } + + @GetMapping("/test/invalid-pms-id") + public void throwInvalidPmsId() throws InvalidPmsIdException { + throw new InvalidPmsIdException("Invalid PMS ID"); + } + + @GetMapping("/test/invalid-transaction-id") + public void throwInvalidTransactionId() throws InvalidTransactionIdException { + throw new InvalidTransactionIdException("Invalid Transaction ID"); + } + + @GetMapping("/test/global-exception") + public void throwGlobalException() throws Exception { + throw new Exception("Internal error"); + } + } +} diff --git a/src/test/java/org/hsbc/service/PmsServiceimpTest.java b/src/test/java/org/hsbc/service/PmsServiceimpTest.java index 06c1c2c..e742f98 100644 --- a/src/test/java/org/hsbc/service/PmsServiceimpTest.java +++ b/src/test/java/org/hsbc/service/PmsServiceimpTest.java @@ -28,6 +28,9 @@ public class PmsServiceimpTest { private PmsEntity asset1; + @Mock + private org.hsbc.service.WalletService walletService; + @BeforeEach void setUp() { // Setup dummy data @@ -41,6 +44,23 @@ void setUp() { // --- Success Tests --- + @Test + void testAddAsset_Success() { + PmsEntity newAsset = new PmsEntity(); + newAsset.setSymbol("GOOGL"); + newAsset.setBuyPrice(100.0); + newAsset.setQuantity(10); + + when(walletService.deductMoney(1000.0)).thenReturn(4000.0); + when(repository.save(any(PmsEntity.class))).thenReturn(newAsset); + + PmsEntity result = service.addAsset(newAsset); + + assertNotNull(result); + verify(walletService, times(1)).deductMoney(1000.0); + assertNotNull(result.getPurchaseDate()); + } + @Test void testGetAssetById_Success() throws InvalidPmsIdException { when(repository.findById(1L)).thenReturn(Optional.of(asset1)); @@ -75,6 +95,23 @@ void testCalculatePL_Success() throws InvalidPmsIdException { assertEquals(200.0, pl); } + @Test + void testCalculatePLPercentage_Success() throws InvalidPmsIdException { + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + // PL is 200. Buying value 1500. % = 200/1500 * 100 = 13.333 + + double plPct = service.calculatePLPercentage(1L); + assertEquals(13.333, plPct, 0.01); + } + + @Test + void testCalculatePLPercentage_ZeroBuyingValue() throws InvalidPmsIdException { + asset1.setBuyPrice(0.0); + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + + assertEquals(0.0, service.calculatePLPercentage(1L)); + } + @Test void testRemoveAsset_Success() throws InvalidPmsIdException { when(repository.findById(1L)).thenReturn(Optional.of(asset1)); @@ -84,6 +121,37 @@ void testRemoveAsset_Success() throws InvalidPmsIdException { verify(repository, times(1)).deleteById(1L); } + @Test + void testGetTotalPortfolioValue() { + PmsEntity asset2 = new PmsEntity(); + asset2.setCurrentPrice(50.0); + asset2.setQuantity(20); // 1000 + // asset1 is 170 * 10 = 1700 + + when(repository.findAll()).thenReturn(Arrays.asList(asset1, asset2)); + + double total = service.getTotalPortfolioValue(); + assertEquals(2700.0, total); + } + + @Test + void testUpdateCurrentPrice_Success() { + when(repository.findAll()).thenReturn(Arrays.asList(asset1)); + when(repository.save(any(PmsEntity.class))).thenReturn(asset1); + + service.updateCurrentPrice("AAPL", 180.0); + + assertEquals(180.0, asset1.getCurrentPrice()); + } + + @Test + void testUpdateCurrentPrice_NotFound() { + when(repository.findAll()).thenReturn(Arrays.asList(asset1)); + + assertThrows(org.hsbc.exception.ResourceNotFoundException.class, + () -> service.updateCurrentPrice("XYZ", 100.0)); + } + // --- Exception Tests (Failure Scenarios) --- @Test diff --git a/src/test/java/org/hsbc/service/WalletServiceimplTest.java b/src/test/java/org/hsbc/service/WalletServiceimplTest.java index 8c600f9..aad5c4d 100644 --- a/src/test/java/org/hsbc/service/WalletServiceimplTest.java +++ b/src/test/java/org/hsbc/service/WalletServiceimplTest.java @@ -8,7 +8,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.web.server.ResponseStatusException; import java.util.Optional; @@ -50,7 +49,7 @@ void testGetBalance() { void testGetBalanceNotFound() { when(repository.findById(1L)).thenReturn(Optional.empty()); - assertThrows(ResponseStatusException.class, () -> service.getBalance()); + assertThrows(org.hsbc.exception.ResourceNotFoundException.class, () -> service.getBalance()); } // 2️⃣ addMoney() @@ -85,7 +84,7 @@ void testDeductMoneyInsufficientBalance() { when(repository.findById(1L)).thenReturn(Optional.of(wallet)); // Trying to deduct 6000 when balance is 5000 - assertThrows(ResponseStatusException.class, () -> service.deductMoney(6000.0)); + assertThrows(org.hsbc.exception.InsufficientBalanceException.class, () -> service.deductMoney(6000.0)); // Ensure save is NEVER called if exception is thrown verify(repository, times(0)).save(any(WalletEntity.class)); diff --git a/src/testbk/java/org/hsbc/PortfolioManagementSystemApplicationTests.java b/src/testbk/java/org/hsbc/PortfolioManagementSystemApplicationTests.java new file mode 100644 index 0000000..004e05e --- /dev/null +++ b/src/testbk/java/org/hsbc/PortfolioManagementSystemApplicationTests.java @@ -0,0 +1,13 @@ +package org.hsbc; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PortfolioManagementSystemApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/src/testbk/java/org/hsbc/controller/DashboardControllerTest.java b/src/testbk/java/org/hsbc/controller/DashboardControllerTest.java new file mode 100644 index 0000000..b177a9e --- /dev/null +++ b/src/testbk/java/org/hsbc/controller/DashboardControllerTest.java @@ -0,0 +1,56 @@ +package org.hsbc.controller; + +import org.hsbc.service.DashboardService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +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; + +@ExtendWith(MockitoExtension.class) +class DashboardControllerTest { + + private MockMvc mockMvc; + + @Mock + private DashboardService service; + + @InjectMocks + private DashboardController controller; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void testGetWalletSummary() throws Exception { + // Arrange + // Scenario: + // Available Balance (Wallet cash): 2000.0 + // Used Balance (Stock value): 8000.0 + // Total Balance (Net worth): 10000.0 + + when(service.getAvailableBalance()).thenReturn(2000.0); + when(service.getTotalUsedBalance()).thenReturn(8000.0); + + // Act & Assert + mockMvc.perform(get("/dashboard/wallet-summary")) + .andExpect(status().isOk()) + + // Verify Math: available (2000) + used (8000) = total (10000) + .andExpect(jsonPath("$.totalBalance").value(10000.0)) + + // Verify individual fields + .andExpect(jsonPath("$.totalUsed").value(8000.0)) + .andExpect(jsonPath("$.availableBalance").value(2000.0)); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/controller/PmsControllerTest.java b/src/testbk/java/org/hsbc/controller/PmsControllerTest.java new file mode 100644 index 0000000..dba1830 --- /dev/null +++ b/src/testbk/java/org/hsbc/controller/PmsControllerTest.java @@ -0,0 +1,144 @@ +package org.hsbc.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.hsbc.entity.PmsEntity; +import org.hsbc.service.PmsService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(PmsController.class) +class PmsControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private PmsService service; + + @Autowired + private ObjectMapper objectMapper; + + // 1️⃣ POST /pms/add + @Test + void testAddAsset() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setId(1L); + asset.setCompanyName("Apple"); + asset.setQuantity(10); + asset.setBuyPrice(100); + asset.setCurrentPrice(120); + + when(service.addAsset(any(PmsEntity.class))).thenReturn(asset); + + mockMvc.perform(post("/api/pms/add") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(asset))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.companyName").value("Apple")) + .andExpect(jsonPath("$.quantity").value(10)); + } + + // 2️⃣ DELETE /pms/remove/{id} + @Test + void testRemoveAsset() throws Exception { + doNothing().when(service).removeAsset(1L); + + mockMvc.perform(delete("/api/pms/remove/1")) + .andExpect(status().isOk()) + .andExpect(content().string("Asset removed successfully")); + } + + // 3️⃣ PUT /pms/update-quantity/{id} + @Test + void testUpdateQuantity() throws Exception { + PmsEntity updated = new PmsEntity(); + updated.setId(1L); + updated.setQuantity(20); + + when(service.updateQuantity(1L, 20)).thenReturn(updated); + + mockMvc.perform(put("/api/pms/update-quantity/1") + .param("quantity", "20")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.quantity").value(20)); + } + + // 4️⃣ GET /pms/pl/{id} + @Test + void testGetPL() throws Exception { + when(service.calculatePL(1L)).thenReturn(200.0); + + mockMvc.perform(get("/api/pms/pl/1")) + .andExpect(status().isOk()) + .andExpect(content().string("200.0")); + } + + @Test + void testGetPL_NotFound() throws Exception { + when(service.calculatePL(99L)).thenThrow(new org.hsbc.exception.InvalidPmsIdException("Not Found")); + + mockMvc.perform(get("/api/pms/pl/99")) + .andExpect(status().isNotFound()); + } + + // 5️⃣ GET /pms/pl-percentage/{id} + @Test + void testGetPLPercentage() throws Exception { + when(service.calculatePLPercentage(1L)).thenReturn(20.0); + + mockMvc.perform(get("/api/pms/pl-percentage/1")) + .andExpect(status().isOk()) + .andExpect(content().string("20.0")); + } + + // 6️⃣ GET /pms/total-value + @Test + void testGetTotalValue() throws Exception { + when(service.getTotalPortfolioValue()).thenReturn(1200.0); + + mockMvc.perform(get("/api/pms/total-value")) + .andExpect(status().isOk()) + .andExpect(content().string("1200.0")); + } + + @Test + void testGetAssetById() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setId(1L); + when(service.getAssetById(1L)).thenReturn(asset); + + mockMvc.perform(get("/api/pms/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(1)); + } + + @Test + void testGetAssetById_NotFound() throws Exception { + when(service.getAssetById(99L)).thenThrow(new org.hsbc.exception.InvalidPmsIdException("Not Found")); + + mockMvc.perform(get("/api/pms/99")) + .andExpect(status().isNotFound()); + } + + @Test + void testUpdatePrice() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setSymbol("AAPL"); + asset.setCurrentPrice(150.0); + + when(service.updateCurrentPrice("AAPL", 150.0)).thenReturn(asset); + + mockMvc.perform(put("/api/pms/update-price/AAPL") + .param("price", "150.0")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.currentPrice").value(150.0)); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/controller/PortfolioControllerTest.java b/src/testbk/java/org/hsbc/controller/PortfolioControllerTest.java new file mode 100644 index 0000000..2651e07 --- /dev/null +++ b/src/testbk/java/org/hsbc/controller/PortfolioControllerTest.java @@ -0,0 +1,160 @@ +package org.hsbc.controller; + +import org.hsbc.entity.PmsEntity; +import org.hsbc.service.PmsService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(PortfolioController.class) +class PortfolioControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private PmsService pmsService; + + @Autowired + private PortfolioController portfolioController; + + private RestTemplate restTemplateMock; + + @BeforeEach + void setUp() { + restTemplateMock = mock(RestTemplate.class); + ReflectionTestUtils.setField(portfolioController, "restTemplate", restTemplateMock); + } + + @Test + void testGetPortfolioSummary() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setBuyPrice(100.0); + asset.setQuantity(10); // Invested: 1000 + asset.setCurrentPrice(120.0); // Current: 1200 + asset.setBuyingValue(1000.0); + + when(pmsService.getAllAssets()).thenReturn(Collections.singletonList(asset)); + + mockMvc.perform(get("/api/portfolio/summary")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.portfolioValue").value(1200.0)) + .andExpect(jsonPath("$.totalInvested").value(1000.0)) + .andExpect(jsonPath("$.totalGain").value(200.0)) + .andExpect(jsonPath("$.gainPercentage").value(20.0)); + } + + @Test + void testGetPortfolioPerformance() throws Exception { + PmsEntity asset = new PmsEntity(); + asset.setSymbol("AAPL"); + asset.setQuantity(10); + asset.setAssetType("Stocks"); + + when(pmsService.getAllAssets()).thenReturn(Collections.singletonList(asset)); + + String mockApiResponse = "{\"data\": [{\"time\": \"2023-01-01\", \"close\": 150.0}]}"; + when(restTemplateMock.getForObject(anyString(), eq(String.class))).thenReturn(mockApiResponse); + + mockMvc.perform(get("/api/portfolio/performance")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].date").value("2023-01-01")) + .andExpect(jsonPath("$[0].value").value(1500)); // 150 * 10 + } + + @Test + void testGetPortfolioPerformance_EmptyAssets() throws Exception { + when(pmsService.getAllAssets()).thenReturn(Collections.emptyList()); + + mockMvc.perform(get("/api/portfolio/performance")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(0))); + } + + @Test + void testGetAssetAllocation() throws Exception { + PmsEntity stock = new PmsEntity(); + stock.setAssetType("Stocks"); + stock.setCurrentPrice(100.0); + stock.setQuantity(10); // 1000 + + PmsEntity crypto = new PmsEntity(); + crypto.setAssetType("Crypto"); + crypto.setCurrentPrice(50.0); + crypto.setQuantity(20); // 1000 + + when(pmsService.getAllAssets()).thenReturn(Arrays.asList(stock, crypto)); + + mockMvc.perform(get("/api/portfolio/allocation")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(2))) + .andExpect(jsonPath("$[*].assetType", containsInAnyOrder("Stocks", "Crypto"))) + .andExpect(jsonPath("$[*].value", containsInAnyOrder(1000.0, 1000.0))); + } + + @Test + void testGetInvestmentBreakdown() throws Exception { + PmsEntity stock = new PmsEntity(); + stock.setAssetType("Stock"); // Should normalize to Stocks + stock.setBuyingValue(1000.0); + + when(pmsService.getAllAssets()).thenReturn(Collections.singletonList(stock)); + + mockMvc.perform(get("/api/portfolio/breakdown")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(1))) + .andExpect(jsonPath("$[0].type").value("Stocks")) + .andExpect(jsonPath("$[0].value").value(1000.0)); + } + + @Test + void testGetInvestmentBreakdown_Empty() throws Exception { + when(pmsService.getAllAssets()).thenReturn(Collections.emptyList()); + + mockMvc.perform(get("/api/portfolio/breakdown")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(4))); // Expects all 4 types with 0 + } + + @Test + void testGetPerformers() throws Exception { + PmsEntity winner = new PmsEntity(); + winner.setSymbol("WIN"); + winner.setBuyPrice(100.0); + winner.setBuyingValue(1000.00); // Set buying value explicit + winner.setCurrentPrice(200.0); + winner.setQuantity(10); + + PmsEntity loser = new PmsEntity(); + loser.setSymbol("LOSE"); + loser.setBuyPrice(100.0); + loser.setBuyingValue(1000.00); // Set buying value explicit + loser.setCurrentPrice(50.0); + loser.setQuantity(10); + + when(pmsService.getAllAssets()).thenReturn(Arrays.asList(winner, loser)); + + mockMvc.perform(get("/api/portfolio/performers")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.topPerformers[0].symbol").value("WIN")) + .andExpect(jsonPath("$.lowestPerformers[0].symbol").value("LOSE")); + } +} diff --git a/src/testbk/java/org/hsbc/controller/StockDataControllerTest.java b/src/testbk/java/org/hsbc/controller/StockDataControllerTest.java new file mode 100644 index 0000000..586f6dc --- /dev/null +++ b/src/testbk/java/org/hsbc/controller/StockDataControllerTest.java @@ -0,0 +1,197 @@ + +package org.hsbc.controller; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; +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 static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; + +@ExtendWith(MockitoExtension.class) +public class StockDataControllerTest { + + private MockMvc mockMvc; + + @Mock + private RestTemplate restTemplate; + + @InjectMocks + private StockDataController stockDataController; + + private final String FLASK_URL = "http://localhost:5000"; + + @BeforeEach + void setUp() { + // 1. Inject the Flask URL value (simulating @Value) + ReflectionTestUtils.setField(stockDataController, "flaskApiUrl", FLASK_URL); + + // 2. Overwrite the hardcoded RestTemplate with our Mock using Reflection + // This is necessary because the controller does 'new RestTemplate()' in the constructor + ReflectionTestUtils.setField(stockDataController, "restTemplate", restTemplate); + + // 3. Build the standalone MockMvc context + mockMvc = MockMvcBuilders.standaloneSetup(stockDataController).build(); + } + + // ========================================== + // 1. GET Stock Tests + // ========================================== + + @Test + void getStock_Success() throws Exception { + String mockResponse = "{\"symbol\":\"AAPL\",\"price\":150.0}"; + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/stocks/AAPL"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/stocks/AAPL")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + @Test + void getStock_NotFound() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow( HttpClientErrorException.NotFound.class); + + mockMvc.perform(get("/api/yfdata/stocks/UNKNOWN")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.error").value("Stock not found")); + } + + @Test + void getStock_ServerError() throws Exception { + when(restTemplate.getForEntity(anyString(), eq(String.class))) + .thenThrow(new RuntimeException("Flask down")); + + mockMvc.perform(get("/api/yfdata/stocks/AAPL")) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.error").exists()); + } + + // ========================================== + // 2. GET Crypto Tests + // ========================================== + + @Test + void getCrypto_Success() throws Exception { + String mockResponse = "{\"symbol\":\"BTC\",\"price\":50000.0}"; + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/crypto/BTC"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/crypto/BTC")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + // ========================================== + // 3. GET Mutual Fund Tests + // ========================================== + + @Test + void getMutualFund_Success() throws Exception { + String mockResponse = "{\"symbol\":\"VFIAX\",\"nav\":400.0}"; + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/mutual-funds/VFIAX"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/mutual-funds/VFIAX")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + // ========================================== + // 4. GET Commodity Tests + // ========================================== + + @Test + void getCommodity_Success() throws Exception { + String mockResponse = "{\"symbol\":\"GC=F\",\"price\":1900.0}"; + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/commodities/GC=F"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/commodities/GC=F")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + // ========================================== + // 5. GET History Tests + // ========================================== + + @Test + void getHistory_DefaultPeriod() throws Exception { + String mockResponse = "{\"history\":[]}"; + // Verify default period is 1MO + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/history/AAPL?period=1MO"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/history/AAPL")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + @Test + void getHistory_CustomPeriod() throws Exception { + String mockResponse = "{\"history\":[]}"; + // Verify custom period 1Y + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/history/AAPL?period=1Y"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/history/AAPL").param("period", "1Y")) + .andExpect(status().isOk()); + } + + // ========================================== + // 6. GET News Tests + // ========================================== + + @Test + void getNews_Success() throws Exception { + String mockResponse = "[{\"title\":\"News 1\"}]"; + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/news/AAPL"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/news/AAPL")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + // ========================================== + // 7. GET Search Tests + // ========================================== + + @Test + void searchAssets_Success() throws Exception { + String mockResponse = "[{\"symbol\":\"AAPL\"}]"; + when(restTemplate.getForEntity(eq(FLASK_URL + "/api/search?q=Apple"), eq(String.class))) + .thenReturn(new ResponseEntity<>(mockResponse, HttpStatus.OK)); + + mockMvc.perform(get("/api/yfdata/search").param("q", "Apple")) + .andExpect(status().isOk()) + .andExpect(content().json(mockResponse)); + } + + @Test + void searchAssets_MissingQuery() throws Exception { + // The controller checks if q is null or empty manually + mockMvc.perform(get("/api/yfdata/search").param("q", "")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.error").value("Query parameter 'q' is required")); + } +} + +// =========================== \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/controller/TransactionControllerTest.java b/src/testbk/java/org/hsbc/controller/TransactionControllerTest.java new file mode 100644 index 0000000..ddbda44 --- /dev/null +++ b/src/testbk/java/org/hsbc/controller/TransactionControllerTest.java @@ -0,0 +1,92 @@ +package org.hsbc.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.hsbc.entity.TransactionEntity; +import org.hsbc.service.TransactionService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@ExtendWith(MockitoExtension.class) +class TransactionControllerTest { + + private MockMvc mockMvc; + private ObjectMapper objectMapper; + + @Mock + private TransactionService service; + + @InjectMocks + private TransactionController controller; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + objectMapper = new ObjectMapper(); + // Required to handle LocalDate serialization properly + objectMapper.findAndRegisterModules(); + } + + // 1️⃣ Add transaction + @Test + void testAddTransaction() throws Exception { + TransactionEntity txn = new TransactionEntity("AAPL", 10, 150.0, LocalDateTime.now(), "BUY"); + txn.setTransactionId(1L); + + when(service.addTransaction(any(TransactionEntity.class))).thenReturn(txn); + + mockMvc.perform(post("/transactions/add") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(txn))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.symbol").value("AAPL")) + .andExpect(jsonPath("$.transactionType").value("BUY")); + } + + // 2️⃣ Get all transactions + @Test + void testGetAllTransactions() throws Exception { + List txnList = Arrays.asList( + new TransactionEntity("AAPL", 10, 150.0, LocalDateTime.now(), "BUY"), + new TransactionEntity("GOOGL", 5, 2000.0, LocalDateTime.now(), "SELL") + ); + + when(service.getAllTransactions()).thenReturn(txnList); + + mockMvc.perform(get("/transactions/all")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.length()").value(2)) + .andExpect(jsonPath("$[0].symbol").value("AAPL")); + } + + // 3️⃣ Get transactions by symbol + @Test + void testGetBySymbol() throws Exception { + List txnList = Arrays.asList( + new TransactionEntity("TSLA", 20, 700.0, LocalDateTime.now(), "BUY") + ); + + when(service.getTransactionsBySymbol("TSLA")).thenReturn(txnList); + + mockMvc.perform(get("/transactions/symbol/TSLA")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.length()").value(1)) + .andExpect(jsonPath("$[0].symbol").value("TSLA")); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/controller/WalletControllerTest.java b/src/testbk/java/org/hsbc/controller/WalletControllerTest.java new file mode 100644 index 0000000..69da6bb --- /dev/null +++ b/src/testbk/java/org/hsbc/controller/WalletControllerTest.java @@ -0,0 +1,71 @@ +package org.hsbc.controller; + +import org.hsbc.service.WalletService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +class WalletControllerTest { + + private MockMvc mockMvc; + + @Mock + private WalletService service; + + @InjectMocks + private WalletController controller; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + // 1️⃣ Show wallet balance + @Test + void testGetBalance() throws Exception { + when(service.getBalance()).thenReturn(5000.0); + + mockMvc.perform(get("/wallet/balance")) + .andExpect(status().isOk()) + .andExpect(content().string("5000.0")); + } + + // 2️⃣ Add money + @Test + void testAddMoney() throws Exception { + // Arrange: Wallet starts at X, adding 1000 results in new balance 6000 + when(service.addMoney(1000.0)).thenReturn(6000.0); + + // Act & Assert + // Note: controller expects @RequestParam, so we use .param("amount", ...) + mockMvc.perform(post("/wallet/add") + .param("amount", "1000.0")) + .andExpect(status().isOk()) + .andExpect(content().string("6000.0")); + } + + // 3️⃣ Deduct money + @Test + void testDeductMoney() throws Exception { + // Arrange: Deducting 500 results in new balance 4500 + when(service.deductMoney(500.0)).thenReturn(4500.0); + + // Act & Assert + mockMvc.perform(post("/wallet/deduct") + .param("amount", "500.0")) + .andExpect(status().isOk()) + .andExpect(content().string("4500.0")); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/service/DashboardServiceTest.java b/src/testbk/java/org/hsbc/service/DashboardServiceTest.java new file mode 100644 index 0000000..786ee2e --- /dev/null +++ b/src/testbk/java/org/hsbc/service/DashboardServiceTest.java @@ -0,0 +1,57 @@ +package org.hsbc.service; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class DashboardServiceTest { + + @Mock + private WalletServiceImpl walletService; + + @Mock + private PmsService pmsService; + + @InjectMocks + private DashboardService dashboardService; + + // 1️⃣ getTotalUsedBalance() + @Test + void testGetTotalUsedBalance() { + // Arrange + double portfolioValue = 5000.0; + when(pmsService.getTotalPortfolioValue()).thenReturn(portfolioValue); + + // Act + double result = dashboardService.getTotalUsedBalance(); + + // Assert + assertEquals(5000.0, result); + verify(pmsService, times(1)).getTotalPortfolioValue(); + } + + // 2️⃣ getAvailableBalance() + @Test + void testGetAvailableBalance() { + // Arrange + double walletBalance = 10000.0; + double portfolioValue = 2000.0; + + when(walletService.getBalance()).thenReturn(walletBalance); + when(pmsService.getTotalPortfolioValue()).thenReturn(portfolioValue); + + // Act + double result = dashboardService.getAvailableBalance(); + + // Assert: 10000 - 2000 = 8000 + assertEquals(8000.0, result); + verify(walletService, times(1)).getBalance(); + verify(pmsService, times(1)).getTotalPortfolioValue(); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/service/PmsServiceimpTest.java b/src/testbk/java/org/hsbc/service/PmsServiceimpTest.java new file mode 100644 index 0000000..e742f98 --- /dev/null +++ b/src/testbk/java/org/hsbc/service/PmsServiceimpTest.java @@ -0,0 +1,183 @@ +package org.hsbc.service; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.hsbc.entity.PmsEntity; +import org.hsbc.exception.InvalidPmsIdException; +import org.hsbc.repo.PmsRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class PmsServiceimpTest { + + @Mock + private PmsRepository repository; + + @InjectMocks + private PmsServiceimp service; + + private PmsEntity asset1; + + @Mock + private org.hsbc.service.WalletService walletService; + + @BeforeEach + void setUp() { + // Setup dummy data + asset1 = new PmsEntity(); + asset1.setId(1L); + asset1.setSymbol("AAPL"); + asset1.setBuyPrice(150.0); + asset1.setCurrentPrice(170.0); + asset1.setQuantity(10); + } + + // --- Success Tests --- + + @Test + void testAddAsset_Success() { + PmsEntity newAsset = new PmsEntity(); + newAsset.setSymbol("GOOGL"); + newAsset.setBuyPrice(100.0); + newAsset.setQuantity(10); + + when(walletService.deductMoney(1000.0)).thenReturn(4000.0); + when(repository.save(any(PmsEntity.class))).thenReturn(newAsset); + + PmsEntity result = service.addAsset(newAsset); + + assertNotNull(result); + verify(walletService, times(1)).deductMoney(1000.0); + assertNotNull(result.getPurchaseDate()); + } + + @Test + void testGetAssetById_Success() throws InvalidPmsIdException { + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + + PmsEntity result = service.getAssetById(1L); + + assertNotNull(result); + assertEquals("AAPL", result.getSymbol()); + } + + @Test + void testUpdateQuantity_Success() throws InvalidPmsIdException { + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + when(repository.save(any(PmsEntity.class))).thenReturn(asset1); + + PmsEntity updated = service.updateQuantity(1L, 20); + + assertEquals(20, updated.getQuantity()); + // Check if buying value updated: 150 * 20 = 3000 + assertEquals(3000.0, updated.getBuyingValue()); + } + + @Test + void testCalculatePL_Success() throws InvalidPmsIdException { + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + + // Buy: 150 * 10 = 1500 + // Current: 170 * 10 = 1700 + // PL: 200 + double pl = service.calculatePL(1L); + + assertEquals(200.0, pl); + } + + @Test + void testCalculatePLPercentage_Success() throws InvalidPmsIdException { + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + // PL is 200. Buying value 1500. % = 200/1500 * 100 = 13.333 + + double plPct = service.calculatePLPercentage(1L); + assertEquals(13.333, plPct, 0.01); + } + + @Test + void testCalculatePLPercentage_ZeroBuyingValue() throws InvalidPmsIdException { + asset1.setBuyPrice(0.0); + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + + assertEquals(0.0, service.calculatePLPercentage(1L)); + } + + @Test + void testRemoveAsset_Success() throws InvalidPmsIdException { + when(repository.findById(1L)).thenReturn(Optional.of(asset1)); + + assertDoesNotThrow(() -> service.removeAsset(1L)); + + verify(repository, times(1)).deleteById(1L); + } + + @Test + void testGetTotalPortfolioValue() { + PmsEntity asset2 = new PmsEntity(); + asset2.setCurrentPrice(50.0); + asset2.setQuantity(20); // 1000 + // asset1 is 170 * 10 = 1700 + + when(repository.findAll()).thenReturn(Arrays.asList(asset1, asset2)); + + double total = service.getTotalPortfolioValue(); + assertEquals(2700.0, total); + } + + @Test + void testUpdateCurrentPrice_Success() { + when(repository.findAll()).thenReturn(Arrays.asList(asset1)); + when(repository.save(any(PmsEntity.class))).thenReturn(asset1); + + service.updateCurrentPrice("AAPL", 180.0); + + assertEquals(180.0, asset1.getCurrentPrice()); + } + + @Test + void testUpdateCurrentPrice_NotFound() { + when(repository.findAll()).thenReturn(Arrays.asList(asset1)); + + assertThrows(org.hsbc.exception.ResourceNotFoundException.class, + () -> service.updateCurrentPrice("XYZ", 100.0)); + } + + // --- Exception Tests (Failure Scenarios) --- + + @Test + void testGetAssetById_NotFound() { + when(repository.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(InvalidPmsIdException.class, () -> { + service.getAssetById(99L); + }); + } + + @Test + void testUpdateQuantity_NotFound() { + when(repository.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(InvalidPmsIdException.class, () -> { + service.updateQuantity(99L, 5); + }); + } + + @Test + void testCalculatePL_NotFound() { + when(repository.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(InvalidPmsIdException.class, () -> { + service.calculatePL(99L); + }); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/service/TransactionServiceimpTest.java b/src/testbk/java/org/hsbc/service/TransactionServiceimpTest.java new file mode 100644 index 0000000..3d43be4 --- /dev/null +++ b/src/testbk/java/org/hsbc/service/TransactionServiceimpTest.java @@ -0,0 +1,151 @@ +package org.hsbc.service; + +import org.hsbc.entity.TransactionEntity; +import org.hsbc.exception.InvalidTransactionIdException; +import org.hsbc.repo.TransactionRepo; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class TransactionSeviceimpTest { + + @Mock + private TransactionRepo repository; + + @InjectMocks + private TransactionSeviceimp service; + + private TransactionEntity transaction; + + @BeforeEach + void setUp() { + transaction = new TransactionEntity(); + transaction.setTransactionId(1L); + transaction.setSymbol("AAPL"); + transaction.setQuantity(10); + transaction.setBuyPrice(150.0); + transaction.setTransactionDate(LocalDateTime.now()); + transaction.setTransactionType("BUY"); + } + + // 1️⃣ addTransaction() + @Test + void testAddTransaction() { + when(repository.save(any(TransactionEntity.class))).thenReturn(transaction); + + TransactionEntity saved = service.addTransaction(transaction); + + assertNotNull(saved); + assertEquals("AAPL", saved.getSymbol()); + verify(repository, times(1)).save(transaction); + } + + // 2️⃣ getAllTransactions() + @Test + void testGetAllTransactions() { + when(repository.findAll()).thenReturn(List.of(transaction)); + + List list = service.getAllTransactions(); + + assertEquals(1, list.size()); + assertEquals(transaction, list.get(0)); + verify(repository, times(1)).findAll(); + } + + // 3️⃣ getTransactionsBySymbol() + @Test + void testGetTransactionsBySymbol() { + when(repository.findBySymbol("AAPL")).thenReturn(List.of(transaction)); + + List list = service.getTransactionsBySymbol("AAPL"); + + assertEquals(1, list.size()); + assertEquals("AAPL", list.get(0).getSymbol()); + verify(repository, times(1)).findBySymbol("AAPL"); + } + + // 4️⃣ getTransactionById() - Success + @Test + void testGetTransactionById_Success() throws InvalidTransactionIdException { + when(repository.findById(1L)).thenReturn(Optional.of(transaction)); + + TransactionEntity found = service.getTransactionById(1L); + + assertNotNull(found); + assertEquals(1L, found.getTransactionId()); + verify(repository, times(1)).findById(1L); + } + + // 5️⃣ getTransactionById() - Failure (Exception) + @Test + void testGetTransactionById_NotFound() { + when(repository.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(InvalidTransactionIdException.class, () -> { + service.getTransactionById(99L); + }); + + verify(repository, times(1)).findById(99L); + } + + // 6️⃣ updateTransaction() - Success + @Test + void testUpdateTransaction_Success() throws InvalidTransactionIdException { + when(repository.findById(1L)).thenReturn(Optional.of(transaction)); + when(repository.save(any(TransactionEntity.class))).thenReturn(transaction); + + TransactionEntity updated = service.updateTransaction(transaction); + + assertNotNull(updated); + verify(repository, times(1)).save(transaction); + } + + // 7️⃣ updateTransaction() - Failure (Exception) + @Test + void testUpdateTransaction_NotFound() { + TransactionEntity newTrans = new TransactionEntity(); + newTrans.setTransactionId(99L); + + when(repository.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(InvalidTransactionIdException.class, () -> { + service.updateTransaction(newTrans); + }); + + verify(repository, never()).save(any()); + } + + // 8️⃣ deleteTransaction() - Success + @Test + void testDeleteTransaction_Success() throws InvalidTransactionIdException { + when(repository.findById(1L)).thenReturn(Optional.of(transaction)); + + assertDoesNotThrow(() -> service.deleteTransaction(1L)); + + verify(repository, times(1)).deleteById(1L); + } + + // 9️⃣ deleteTransaction() - Failure (Exception) + @Test + void testDeleteTransaction_NotFound() { + when(repository.findById(99L)).thenReturn(Optional.empty()); + + assertThrows(InvalidTransactionIdException.class, () -> { + service.deleteTransaction(99L); + }); + + verify(repository, never()).deleteById(anyLong()); + } +} \ No newline at end of file diff --git a/src/testbk/java/org/hsbc/service/WalletServiceimplTest.java b/src/testbk/java/org/hsbc/service/WalletServiceimplTest.java new file mode 100644 index 0000000..aad5c4d --- /dev/null +++ b/src/testbk/java/org/hsbc/service/WalletServiceimplTest.java @@ -0,0 +1,92 @@ +package org.hsbc.service; + +import org.hsbc.entity.WalletEntity; +import org.hsbc.repo.WalletRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class WalletServiceImplTest { + + @Mock + private WalletRepository repository; + + @InjectMocks + private WalletServiceImpl service; + + private WalletEntity wallet; + + @BeforeEach + void setUp() { + wallet = new WalletEntity(); + wallet.setId(1L); + wallet.setBalance(5000.0); + } + + // 1️⃣ getBalance() - Success + @Test + void testGetBalance() { + when(repository.findById(1L)).thenReturn(Optional.of(wallet)); + + double balance = service.getBalance(); + + assertEquals(5000.0, balance); + } + + // ❌ getBalance() - Not Found + @Test + void testGetBalanceNotFound() { + when(repository.findById(1L)).thenReturn(Optional.empty()); + + assertThrows(org.hsbc.exception.ResourceNotFoundException.class, () -> service.getBalance()); + } + + // 2️⃣ addMoney() + @Test + void testAddMoney() { + when(repository.findById(1L)).thenReturn(Optional.of(wallet)); + when(repository.save(any(WalletEntity.class))).thenReturn(wallet); + + double newBalance = service.addMoney(1000.0); + + // 5000 + 1000 = 6000 + assertEquals(6000.0, newBalance); + verify(repository, times(1)).save(wallet); + } + + // 3️⃣ deductMoney() - Success + @Test + void testDeductMoney() { + when(repository.findById(1L)).thenReturn(Optional.of(wallet)); + when(repository.save(any(WalletEntity.class))).thenReturn(wallet); + + double newBalance = service.deductMoney(2000.0); + + // 5000 - 2000 = 3000 + assertEquals(3000.0, newBalance); + verify(repository, times(1)).save(wallet); + } + + // ❌ deductMoney() - Insufficient Balance + @Test + void testDeductMoneyInsufficientBalance() { + when(repository.findById(1L)).thenReturn(Optional.of(wallet)); + + // Trying to deduct 6000 when balance is 5000 + assertThrows(org.hsbc.exception.InsufficientBalanceException.class, () -> service.deductMoney(6000.0)); + + // Ensure save is NEVER called if exception is thrown + verify(repository, times(0)).save(any(WalletEntity.class)); + } +} \ No newline at end of file diff --git a/src/testbk/resources/mockito-extensions/org.mockito.plugins.MockMaker b/src/testbk/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000..1f0955d --- /dev/null +++ b/src/testbk/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline