From 4b7424d324839442aba61a0c3e95356c8454d6e8 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Thu, 5 Feb 2026 13:33:17 +0000
Subject: [PATCH 1/5] Putting log file updated
---
.gitignore | 9 +
logs/pms-application.log | 240 ++++++++++++++++++
pom.xml | 4 +
.../java/org/hsbc/logging/LoggingAspect.java | 57 +++++
4 files changed, 310 insertions(+)
create mode 100644 src/main/java/org/hsbc/logging/LoggingAspect.java
diff --git a/.gitignore b/.gitignore
index 0758503..5dc85f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,12 @@ build/
### VS Code ###
.vscode/
Backend/RECOMMENDATION_SERVICE.md
+
+
+# ----------------------------
+# Log files
+# ----------------------------
+logs/
+*.log
+*.log.*
+
diff --git a/logs/pms-application.log b/logs/pms-application.log
index e69de29..abe80de 100644
--- a/logs/pms-application.log
+++ b/logs/pms-application.log
@@ -0,0 +1,240 @@
+2026-02-05 13:18:53 INFO o.hsbc.controller.PmsControllerTest - Starting PmsControllerTest using Java 22.0.2 with PID 13868 (started by Administrator in C:\Users\Administrator\PortfolioManagementSystem)
+2026-02-05 13:18:53 DEBUG o.hsbc.controller.PmsControllerTest - Running with Spring Boot v3.2.4, Spring v6.1.5
+2026-02-05 13:18:53 INFO o.hsbc.controller.PmsControllerTest - No active profile set, falling back to 1 default profile: "default"
+2026-02-05 13:18:55 INFO o.s.b.t.m.w.SpringBootMockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:55 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:55 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms
+2026-02-05 13:18:55 INFO o.hsbc.controller.PmsControllerTest - Started PmsControllerTest in 2.331 seconds (process running for 7.338)
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Request received for commodity: GC=F
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/commodities/GC=F
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Successfully fetched commodity data for: GC=F
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Request received for mutual fund: VFIAX
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/mutual-funds/VFIAX
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Successfully fetched mutual fund data for: VFIAX
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Request received for history: AAPL with period: 1MO, interval: null
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AAPL?period=1MO
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Successfully fetched history for: AAPL (1MO, null)
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Request received for crypto: BTC
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/crypto/BTC
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Successfully fetched crypto data for: BTC
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Search request received with query: Apple
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/search?q=Apple
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Search completed successfully for query: Apple
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Request received for stock: AAPL
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/AAPL
+2026-02-05 13:18:56 ERROR o.h.controller.StockDataController - Error fetching stock data for AAPL: Flask down
+java.lang.RuntimeException: Flask down
+ 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.test.web.servlet.MockMvc.perform(MockMvc.java:201)
+ at org.hsbc.controller.StockDataControllerTest.getStock_ServerError(StockDataControllerTest.java:81)
+ 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:1597)
+ 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:1597)
+ 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.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56)
+ at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184)
+ at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148)
+ at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:122)
+ at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
+ at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
+ at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
+ at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:56 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:56 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Request received for stock: AAPL
+2026-02-05 13:18:56 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/AAPL
+2026-02-05 13:18:56 INFO o.h.controller.StockDataController - Successfully fetched stock data for: AAPL
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - Request received for stock: UNKNOWN
+2026-02-05 13:18:57 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/stocks/UNKNOWN
+2026-02-05 13:18:57 WARN o.h.controller.StockDataController - Stock not found: UNKNOWN
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - Search request received with query:
+2026-02-05 13:18:57 WARN o.h.controller.StockDataController - Empty search query received
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - Request received for news: AAPL
+2026-02-05 13:18:57 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/news/AAPL
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - Successfully fetched news for: AAPL
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - Request received for history: AAPL with period: 1Y, interval: null
+2026-02-05 13:18:57 DEBUG o.h.controller.StockDataController - Calling Flask API: http://localhost:5000/api/history/AAPL?period=1Y
+2026-02-05 13:18:57 INFO o.h.controller.StockDataController - Successfully fetched history for: AAPL (1Y, null)
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 1 ms
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.s.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Initializing Servlet ''
+2026-02-05 13:18:57 INFO o.s.t.w.s.TestDispatcherServlet - Completed initialization in 0 ms
+2026-02-05 13:18:57 INFO o.s.t.c.s.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [org.hsbc.PortfolioManagementSystemApplicationTests]: PortfolioManagementSystemApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
+2026-02-05 13:18:57 INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration org.hsbc.PortfolioManagementSystemApplication for test class org.hsbc.PortfolioManagementSystemApplicationTests
+2026-02-05 13:18:58 INFO o.h.PortfolioManagementSystemApplicationTests - Starting PortfolioManagementSystemApplicationTests using Java 22.0.2 with PID 13868 (started by Administrator in C:\Users\Administrator\PortfolioManagementSystem)
+2026-02-05 13:18:58 DEBUG o.h.PortfolioManagementSystemApplicationTests - Running with Spring Boot v3.2.4, Spring v6.1.5
+2026-02-05 13:18:58 INFO o.h.PortfolioManagementSystemApplicationTests - No active profile set, falling back to 1 default profile: "default"
+2026-02-05 13:18:58 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2026-02-05 13:18:58 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 92 ms. Found 3 JPA repository interfaces.
+2026-02-05 13:18:59 INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-05 13:18:59 INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.4.4.Final
+2026-02-05 13:18:59 INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-05 13:18:59 INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
+2026-02-05 13:18:59 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
+2026-02-05 13:19:00 INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@1928930
+2026-02-05 13:19:00 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
+2026-02-05 13:19:01 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-05 13:19:01 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
+2026-02-05 13:19:02 INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used.
+2026-02-05 13:19:02 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:19: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-05 13:19:03 INFO o.h.PortfolioManagementSystemApplicationTests - Started PortfolioManagementSystemApplicationTests in 5.63 seconds (process running for 15.668)
+2026-02-05 13:19:04 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
+2026-02-05 13:19:04 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
+2026-02-05 13:19:04 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
+2026-02-05 13:22:21 INFO o.h.PortfolioManagementSystemApplication - Starting PortfolioManagementSystemApplication using Java 22.0.2 with PID 4240 (C:\Users\Administrator\PortfolioManagementSystem\target\classes started by Administrator in C:\Users\Administrator\PortfolioManagementSystem)
+2026-02-05 13:22:21 DEBUG o.h.PortfolioManagementSystemApplication - Running with Spring Boot v3.2.4, Spring v6.1.5
+2026-02-05 13:22:21 INFO o.h.PortfolioManagementSystemApplication - No active profile set, falling back to 1 default profile: "default"
+2026-02-05 13:22:22 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2026-02-05 13:22:22 INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 61 ms. Found 3 JPA repository interfaces.
+2026-02-05 13:22:22 INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http)
+2026-02-05 13:22:22 INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
+2026-02-05 13:22:22 INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.19]
+2026-02-05 13:22:23 INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2026-02-05 13:22:23 INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1891 ms
+2026-02-05 13:22:23 INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2026-02-05 13:22:23 INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.4.4.Final
+2026-02-05 13:22:23 INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2026-02-05 13:22:23 INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
+2026-02-05 13:22:23 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
+2026-02-05 13:22:24 INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@64f3991e
+2026-02-05 13:22:24 INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
+2026-02-05 13:22:25 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-05 13:22:25 INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
+2026-02-05 13:22:26 INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used.
+2026-02-05 13:22:26 INFO o.h.controller.StockDataController - StockDataController initialized
+2026-02-05 13:22:27 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-05 13:22:27 INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path ''
+2026-02-05 13:22:27 INFO o.h.PortfolioManagementSystemApplication - Started PortfolioManagementSystemApplication in 7.273 seconds (process running for 7.744)
diff --git a/pom.xml b/pom.xml
index a2978a2..c0328b1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,6 +69,10 @@
spring-boot-starter-test
test
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
diff --git a/src/main/java/org/hsbc/logging/LoggingAspect.java b/src/main/java/org/hsbc/logging/LoggingAspect.java
new file mode 100644
index 0000000..61905cf
--- /dev/null
+++ b/src/main/java/org/hsbc/logging/LoggingAspect.java
@@ -0,0 +1,57 @@
+package org.hsbc.logging;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Aspect
+@Component
+public class LoggingAspect {
+
+ private static final Logger log =
+ LoggerFactory.getLogger(LoggingAspect.class);
+
+ // 🔹 Apply to all controller & service methods
+ @Pointcut("execution(* org.hsbc.controller..*(..)) || execution(* org.hsbc.service..*(..))")
+ public void applicationMethods() {}
+
+ @Around("applicationMethods()")
+ public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
+
+ String className = joinPoint.getTarget().getClass().getSimpleName();
+ String methodName = joinPoint.getSignature().getName();
+
+ log.info("➡️ ENTER: {}.{}() with arguments = {}",
+ className,
+ methodName,
+ joinPoint.getArgs());
+
+ long start = System.currentTimeMillis();
+
+ try {
+ Object result = joinPoint.proceed();
+
+ long timeTaken = System.currentTimeMillis() - start;
+
+ log.info("✅ EXIT: {}.{}() | Time = {} ms | Result = {}",
+ className,
+ methodName,
+ timeTaken,
+ result);
+
+ return result;
+
+ } catch (Exception ex) {
+
+ log.error("❌ EXCEPTION in {}.{}() | Message = {}",
+ className,
+ methodName,
+ ex.getMessage(),
+ ex);
+
+ throw ex;
+ }
+ }
+}
From 77beda412f523cb29be953ae44f5f2257efa3d5f Mon Sep 17 00:00:00 2001
From: dhananjay-k-s
Date: Thu, 5 Feb 2026 21:06:24 +0530
Subject: [PATCH 2/5] custom exception handling
merging custom exception handling
---
.../org/hsbc/exception/ErrorResponse.java | 62 ++++++++++++++
.../exception/GlobalExceptionHandler.java | 64 ++++++++++++++
.../InsufficientBalanceException.java | 7 ++
.../exception/ResourceNotFoundException.java | 7 ++
.../java/org/hsbc/service/PmsServiceimp.java | 83 +++++++++----------
.../org/hsbc/service/WalletServiceImpl.java | 15 ++--
6 files changed, 183 insertions(+), 55 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
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/main/java/org/hsbc/service/PmsServiceimp.java b/src/main/java/org/hsbc/service/PmsServiceimp.java
index 3128496..63c0a40 100644
--- a/src/main/java/org/hsbc/service/PmsServiceimp.java
+++ b/src/main/java/org/hsbc/service/PmsServiceimp.java
@@ -1,6 +1,5 @@
package org.hsbc.service;
-
//Import statemnts
import org.hsbc.entity.PmsEntity;
import org.hsbc.exception.InvalidPmsIdException;
@@ -8,40 +7,37 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.stereotype.Service;
-import org.springframework.web.server.ResponseStatusException;
-
import java.time.LocalDate;
+import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class PmsServiceimp implements PmsService {
- private static final Logger log =
- LoggerFactory.getLogger(PmsServiceimp.class);
- @Autowired
- private PmsRepository repository;
-
- @Autowired
- private WalletService walletService;
-
- // 1️⃣ Add Asset
- @Override
- public PmsEntity addAsset(PmsEntity asset) {
- // Calculate total cost
- double totalCost = asset.getBuyPrice() * asset.getQuantity();
-
- // Check and deduct from wallet (this will throw exception if insufficient balance)
- walletService.deductMoney(totalCost);
-
- // Set purchase date and buying value
- asset.setPurchaseDate(LocalDate.now());
- asset.setBuyingValue(totalCost);
-
- return repository.save(asset);
- }
+ private static final Logger log = LoggerFactory.getLogger(PmsServiceimp.class);
+ @Autowired
+ private PmsRepository repository;
+
+ @Autowired
+ private WalletService walletService;
+
+ // 1️⃣ Add Asset
+ @Override
+ public PmsEntity addAsset(PmsEntity asset) {
+ // Calculate total cost
+ double totalCost = asset.getBuyPrice() * asset.getQuantity();
+
+ // Check and deduct from wallet (this will throw exception if insufficient
+ // balance)
+ walletService.deductMoney(totalCost);
+
+ // Set purchase date and buying value
+ asset.setPurchaseDate(LocalDate.now());
+ asset.setBuyingValue(totalCost);
+
+ return repository.save(asset);
+ }
// 2️⃣ Remove Asset
@Override
@@ -80,7 +76,8 @@ public double calculatePLPercentage(Long id) throws InvalidPmsIdException {
double buyingValue = asset.getBuyPrice() * asset.getQuantity();
double pl = calculatePL(id);
- if (buyingValue == 0) return 0;
+ if (buyingValue == 0)
+ return 0;
return (pl / buyingValue) * 100;
}
@@ -93,6 +90,7 @@ public double getTotalPortfolioValue() {
.mapToDouble(a -> a.getCurrentPrice() * a.getQuantity())
.sum();
}
+
public PmsServiceimp(PmsRepository repository) {
this.repository = repository;
}
@@ -101,6 +99,7 @@ public PmsServiceimp(PmsRepository repository) {
public List getAllAssets() {
return repository.findAll();
}
+
@Override
public PmsEntity getAssetById(Long id) throws InvalidPmsIdException {
Optional optAsset = repository.findById(id);
@@ -120,22 +119,16 @@ public PmsEntity updateCurrentPrice(String symbol, double newPrice) {
return repository.save(asset);
}
}
- throw new ResponseStatusException(
- HttpStatus.NOT_FOUND,
- "Asset not found with symbol " + symbol
- );
+ throw new org.hsbc.exception.ResourceNotFoundException("Asset not found with symbol " + symbol);
}
-//
-// public PmsEntity findAllPms(long id) throws InvalidException {
-// Optional optProduct = repository.findById(id);
-// PmsEntity pmsEntity = optProduct.orElseThrow(
-// ()->new InvalidException("Id is not valid: " + id)
-// );
-//
-// return pmsEntity;
-// }
-
-
-
+ //
+ // public PmsEntity findAllPms(long id) throws InvalidException {
+ // Optional optProduct = repository.findById(id);
+ // PmsEntity pmsEntity = optProduct.orElseThrow(
+ // ()->new InvalidException("Id is not valid: " + id)
+ // );
+ //
+ // return pmsEntity;
+ // }
}
\ No newline at end of file
diff --git a/src/main/java/org/hsbc/service/WalletServiceImpl.java b/src/main/java/org/hsbc/service/WalletServiceImpl.java
index f947f7d..6053d24 100644
--- a/src/main/java/org/hsbc/service/WalletServiceImpl.java
+++ b/src/main/java/org/hsbc/service/WalletServiceImpl.java
@@ -4,15 +4,12 @@
import org.hsbc.repo.WalletRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
-import org.springframework.web.server.ResponseStatusException;
@Service
-public class WalletServiceImpl implements WalletService{
+public class WalletServiceImpl implements WalletService {
- private static final Logger log =
- LoggerFactory.getLogger(WalletServiceImpl.class);
+ private static final Logger log = LoggerFactory.getLogger(WalletServiceImpl.class);
private final WalletRepository repository;
@@ -22,8 +19,7 @@ public WalletServiceImpl(WalletRepository repository) {
private WalletEntity getWallet() {
return repository.findById(1L)
- .orElseThrow(() -> new ResponseStatusException(
- HttpStatus.NOT_FOUND, "Wallet not found"));
+ .orElseThrow(() -> new org.hsbc.exception.ResourceNotFoundException("Wallet not found"));
}
@Override
@@ -44,15 +40,14 @@ public double deductMoney(double amount) {
WalletEntity wallet = getWallet();
if (wallet.getBalance() < amount) {
- throw new ResponseStatusException(
- HttpStatus.BAD_REQUEST, "Insufficient balance");
+ throw new org.hsbc.exception.InsufficientBalanceException("Insufficient balance");
}
wallet.setBalance(wallet.getBalance() - amount);
repository.save(wallet);
return wallet.getBalance();
}
-
+
@Override
public WalletEntity getWalletSummary() {
return getWallet();
From e0453c693a19223280805965fe08ab792733b8b6 Mon Sep 17 00:00:00 2001
From: dhananjay-k-s
Date: Thu, 5 Feb 2026 21:30:20 +0530
Subject: [PATCH 3/5] Test cases increased
This is to increase the test coverage
---
.../hsbc/controller/PmsControllerTest.java | 59 ++++++-
.../controller/PortfolioControllerTest.java | 160 ++++++++++++++++++
.../hsbc/controller/WalletControllerTest.java | 27 ++-
.../exception/GlobalExceptionHandlerTest.java | 96 +++++++++++
.../org/hsbc/service/PmsServiceimpTest.java | 68 ++++++++
.../hsbc/service/WalletServiceimplTest.java | 5 +-
6 files changed, 401 insertions(+), 14 deletions(-)
create mode 100644 src/test/java/org/hsbc/controller/PortfolioControllerTest.java
create mode 100644 src/test/java/org/hsbc/exception/GlobalExceptionHandlerTest.java
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/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/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));
From 58596571f8cca54b9f9864e732649a4091b88867 Mon Sep 17 00:00:00 2001
From: dhananjay-k-s
Date: Thu, 5 Feb 2026 21:50:20 +0530
Subject: [PATCH 4/5] test cases increased
---
.../controller/StockDataControllerTest.java | 427 ++++++++++--------
.../java/org/hsbc/entity/PmsEntityTest.java | 83 ++++
.../hsbc/entity/TransactionEntityTest.java | 64 +++
.../org/hsbc/entity/WalletEntityTest.java | 40 ++
.../hsbc/exception/ExceptionClassesTest.java | 77 ++++
5 files changed, 507 insertions(+), 184 deletions(-)
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
diff --git a/src/test/java/org/hsbc/controller/StockDataControllerTest.java b/src/test/java/org/hsbc/controller/StockDataControllerTest.java
index 586f6dc..c772fbe 100644
--- a/src/test/java/org/hsbc/controller/StockDataControllerTest.java
+++ b/src/test/java/org/hsbc/controller/StockDataControllerTest.java
@@ -1,197 +1,256 @@
-
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.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.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/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());
+ }
+}
From 41d2066475abbe6a881248eb70ee59273fd888e5 Mon Sep 17 00:00:00 2001
From: dhananjay-k-s
Date: Thu, 5 Feb 2026 16:43:35 +0000
Subject: [PATCH 5/5] adding import
---
src/test/java/org/hsbc/controller/StockDataControllerTest.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/test/java/org/hsbc/controller/StockDataControllerTest.java b/src/test/java/org/hsbc/controller/StockDataControllerTest.java
index c772fbe..5b493c7 100644
--- a/src/test/java/org/hsbc/controller/StockDataControllerTest.java
+++ b/src/test/java/org/hsbc/controller/StockDataControllerTest.java
@@ -12,8 +12,7 @@
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
+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;