diff --git a/.gitignore b/.gitignore index 667aaef..9192534 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ build/ ### VS Code ### .vscode/ + +### Runtime logs ### +logs/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dbd6638 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog + +## [0.0.1-SNAPSHOT] - 2026-05-21 +### Added +- Spring Boot 3.5 REST API with Oracle XE backend +- Package-measurement sequence conversion endpoint (`GET /convert-measurements`) +- History CRUD endpoints (`GET/PUT/PATCH/DELETE /history`) +- JPA entity `HistoryRecord` with auto-generated sequence IDs +- DTO `ConversionResponse` for API responses +- Rolling log appender with 7-day retention (`logs/pkc-api.log`) +- Sequence conversion algorithm supporting: + - Count encoding via leading `z` (+26 each) + non-z terminator + - Value reading with `_` as zero-value character + - `z` value character contributing 27 +- 8 test cases for conversion algorithm (all passing) +- Input validation with `@NotBlank` and `@Pattern(regexp = "[a-z_]+")` +- Global exception handler (`@RestControllerAdvice`) returning structured error JSON +- `ConversionResponse` DTO wrapping response in `{"packages": [...]}` format diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..231b61e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM eclipse-temurin:17-jre-alpine +COPY target/oraclequantapi-0.0.1-SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "/app.jar"] diff --git a/README-DOCKER.md b/README-DOCKER.md new file mode 100644 index 0000000..e41cfdd --- /dev/null +++ b/README-DOCKER.md @@ -0,0 +1,90 @@ +# Docker Setup for OracleQuant PKC API + +Run the entire project with a single command using Docker. + +## Prerequisites + +- Docker Desktop installed and running +- Java 17 and Maven (only for the initial JAR build) + +## How to Build and Run with Docker + +```bash +# 1. Build the JAR file +mvn clean package -DskipTests + +# 2. Build Docker images and start containers +docker-compose up --build +``` + +The application will be available at `http://localhost:8080`. + +> **Note:** Oracle XE takes 2–3 minutes to start for the first time. The `pkc-api` service waits for the database health check to pass before starting. + +## How to Stop + +```bash +docker-compose down +``` + +To also remove the persisted database volume: + +```bash +docker-compose down -v +``` + +## How to Test + +All endpoints are available at `http://localhost:8080`. + +### Convert Measurements + +```bash +curl "http://localhost:8080/convert-measurements?input=abbcc" +``` + +Response: +```json +{"packages": [2, 6]} +``` + +### Get All History Records + +```bash +curl "http://localhost:8080/history" +``` + +### Get Single History Record + +```bash +curl "http://localhost:8080/history/1" +``` + +### Update History Record + +```bash +curl -X PUT "http://localhost:8080/history/1" \ + -H "Content-Type: application/json" \ + -d '{"input":"aa","output":"[1]","sourceIpAddress":"10.0.0.1","timestamp":"2026-05-21T10:00:00"}' +``` + +### Partial Update History Record + +```bash +curl -X PATCH "http://localhost:8080/history/1" \ + -H "Content-Type: application/json" \ + -d '{"input":"aa"}' +``` + +### Delete All History Records + +```bash +curl -X DELETE "http://localhost:8080/history" +``` + +### View Container Logs + +```bash +docker-compose logs -f pkc-api +docker-compose logs -f oracle-db +``` diff --git a/README.md b/README.md index b1cccfd..c197030 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,339 @@ -## Submission Instructions - -To submit your Oracle JAVA Spring Boot Maven project as a solution, please follow these steps: - -### Step 1: Install git on your PC -- Install "git" as shown in this tutorial: [How to install git](https://youtu.be/iYkLrXobBbA?si=_l0haibv_X9NpIjJ) -- Open command prompt and run - ```bash - git version - ``` -- If you see the version, then git is successfully installed. - -### Step 2: Fork the Repository -- Navigate to [this repository](https://github.com/CodelineAtyab/oraclequantapi) provided by Codeline. -- Click on the "Fork" button at the top-right corner of the page to create a copy of the repository under your own GitHub account. - -### Step 3: Clone the Forked Repository -- Open your terminal or command prompt. -- Clone the forked repository to your local machine using the following command: - ```bash - git clone https://github.com/your-username/repo-name.git - ``` - -### Step 4: Create a new branch -- Navigate to the cloned repository directory - ```bash - cd repo-name - ``` -- Create a new branch for your code submissions (Replace your-name with your name in your-name-submission-branch): - ```bash - git checkout -b your-name-submission-branch - ``` - - -### Step 5: Add Your Code -- Implement the API - -### Step 6: Commit your changes -- Run the following commands in order to commit your changes: - ```bash - git add * - git commit -m "Meaningful commit message here" - ``` - -### Step 7: Push Your Branch to GitHub -- Run the following commands to upload the changes to the forked github repository (Replace your-name with your name in your-name-submission-branch): - ```bash - git push origin your-name-submission-branch - ``` - -### Step 8: Create a Pull Request -- Go to your forked repository on GitHub. -- You should see a prompt to create a pull request. Click on "Compare & pull request". -- Provide a title and description for your pull request, then click "Create pull request". - -### Step 9: Notify Codeline -- Notify on slack that you have created a PR for your solution. - -## Note: If you face any issues in the process above, Please do the following: -- Watch [this youtube tutorial](https://www.youtube.com/watch?v=a_FLqX3vGR4) -- Contact Ikhlas or Atyab. +# OracleQuant PKC API + +## Project Overview + +The OracleQuant PKC (Package Measurement Conversion) API converts encoded letter sequences into integer package measurements. Given a string of characters `a-z` and underscores, it parses packages using a count-value encoding scheme and returns a JSON object containing an array of integers. The API also maintains a full history of conversion requests with CRUD endpoints for record management. + +Built with Java 17, Spring Boot 3.5, Oracle XE 21c, and Maven. + +## Prerequisites + +- Oracle OpenJDK 17 +- Maven 3.8+ +- Oracle XE 21c (with `pkc_user` created) +- Oracle Linux (for deployment) + +--- + +## Running Tests + +Run the unit tests (no database required): + +```bash +# All tests +mvn test + +# Single test class +mvn test -Dtest=SequenceServiceTest + +# Single test method +mvn test -Dtest=SequenceServiceTest#testAa +``` + +### Test Coverage + +| Test | Input | Expected | +|------|-------|----------| +| `testAa` | `aa` | `[1]` | +| `testAbbcc` | `abbcc` | `[2, 6]` | +| `testDz_a_aazzaaa` | `dz_a_aazzaaa` | `[28, 1]` | +| `testA_` | `a_` | `[0]` | +| `testAbcdabcdab` | `abcdabcdab` | `[2, 7, 7]` | +| `testAbcdabcdab_` | `abcdabcdab_` | `[2, 7, 7, 0]` | +| `testZdaaaaaaaabaaaaaaaabaaaaaaaabbaa` | `zdaaaaaaaabaaaaaaaabaaaaaaaabbaa` | `[34]` | +| `testZa_a_a_a_a_a_a_a_a_a_a_a_a_azaaa` | `za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa` | `[40, 1]` | + +--- + +## How to Build and Run Locally + +```bash +# Clone the repository +git clone +cd oraclequantapi + +# Build the JAR (requires Oracle XE for full build) +mvn clean package + +# Build the JAR and skip tests (no database needed) +mvn clean package -DskipTests + +# Run the application +java -jar target/oraclequantapi-0.0.1-SNAPSHOT.jar +``` + +The application starts on port `8080` by default. + +--- + +## Database Configuration + +### Create Database User + +Connect to your Oracle XE database and run: + +```sql +ALTER SESSION SET CONTAINER=XEPDB1; +CREATE USER pkc_user IDENTIFIED BY pkc_password; +GRANT CONNECT, RESOURCE TO pkc_user; +GRANT UNLIMITED TABLESPACE TO pkc_user; +GRANT CREATE SEQUENCE TO pkc_user; +GRANT CREATE TABLE TO pkc_user; +``` + +### Application Properties + +Configured in `src/main/resources/application.properties`: + +```properties +server.port=8080 + +spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1 +spring.datasource.username=pkc_user +spring.datasource.password=pkc_password +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver + +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect + +logging.level.com.oraclequantapi=DEBUG +``` + +Hibernate `ddl-auto=update` creates the `conversion_history` table automatically on startup. + +--- + +## REST API Endpoints + +### Convert Measurements + +``` +GET /convert-measurements?input=abbcc +``` + +```bash +curl "http://localhost:8080/convert-measurements?input=abbcc" +``` + +Response (200 OK): +```json +{"packages": [2, 6]} +``` + +#### Input Validation + +- `input` parameter is required and cannot be blank. +- Only lowercase letters (`a-z`) and underscores (`_`) are allowed. +- Invalid input returns `400 Bad Request`: +```json +{"error": "Invalid input: ..."} +``` + +#### Auto-Evaluation Reference Table + +| Request (`?input=...`) | Response (`{"packages": [...]}`) | +|------------------------|----------------------------------| +| `aa` | `[1]` | +| `abbcc` | `[2, 6]` | +| `dz_a_aazzaaa` | `[28, 1]` | +| `a_` | `[0]` | +| `abcdabcdab` | `[2, 7, 7]` | +| `abcdabcdab_` | `[2, 7, 7, 0]` | +| `zdaaaaaaaabaaaaaaaabaaaaaaaabbaa` | `[34]` | +| `za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa` | `[40, 1]` | + +### Get All History Records + +``` +GET /history +``` + +```bash +curl "http://localhost:8080/history" +``` + +Response (200 OK): +```json +[ + { + "id": 1, + "timestamp": "2026-05-21T09:30:00", + "sourceIpAddress": "127.0.0.1", + "input": "abbcc", + "output": "[2, 6]" + } +] +``` + +### Get Single History Record + +``` +GET /history/{id} +``` + +```bash +curl "http://localhost:8080/history/1" +``` + +Response (200 OK): +```json +{ + "id": 1, + "timestamp": "2026-05-21T09:30:00", + "sourceIpAddress": "127.0.0.1", + "input": "abbcc", + "output": "[2, 6]" +} +``` + +Returns `404 Not Found` if the record does not exist. + +### Update History Record + +``` +PUT /history/{id} +``` + +```bash +curl -X PUT "http://localhost:8080/history/1" \ + -H "Content-Type: application/json" \ + -d '{"input":"aa","output":"[1]","sourceIpAddress":"10.0.0.1","timestamp":"2026-05-21T10:00:00"}' +``` + +Response: the updated record (200 OK). + +### Partial Update History Record + +``` +PATCH /history/{id} +``` + +```bash +curl -X PATCH "http://localhost:8080/history/1" \ + -H "Content-Type: application/json" \ + -d '{"input":"aa"}' +``` + +Response: the partially updated record (200 OK). + +### Delete All History Records + +``` +DELETE /history +``` + +```bash +curl -X DELETE "http://localhost:8080/history" +``` + +Response: `204 No Content`. + +--- + +## Postman Testing + +1. Create a new **GET** request to `http://localhost:8080/convert-measurements` +2. Add a **Query Param**: `input` = `aa` +3. Send → expect `{"packages": [1]}` +4. All history endpoints are **GET/PUT/PATCH/DELETE** on `http://localhost:8080/history` + +### Collection of Test Requests + +| Method | URL | Notes | +|--------|-----|-------| +| `GET` | `/convert-measurements?input=aa` | Basic single package | +| `GET` | `/convert-measurements?input=abbcc` | Multi-package | +| `GET` | `/convert-measurements?input=dz_a_aazzaaa` | z in count + value | +| `GET` | `/convert-measurements?input=a_` | Underscore = 0 | +| `GET` | `/history` | Fetch all history | +| `GET` | `/history/1` | Fetch by ID | +| `PUT` | `/history/1` | Full update (JSON body) | +| `PATCH` | `/history/1` | Partial update (JSON body) | +| `DELETE` | `/history` | Clear all history | + +--- + +## Deploy to Oracle Linux via SSH + +### Step 1: Build the JAR + +```bash +# On your local machine +mvn clean package -DskipTests +``` + +### Step 2: Copy to VM using SCP + +```bash +scp target/oraclequantapi-0.0.1-SNAPSHOT.jar oracle@:/home/oracle/ +``` + +### Step 3: SSH into VM and Run + +```bash +ssh oracle@ + +# Verify Java 17 +java -version + +# Run the application +cd /home/oracle +java -jar oraclequantapi-0.0.1-SNAPSHOT.jar +``` + +### Step 4: Run as a Background Service + +For persistent execution after logout: + +```bash +nohup java -jar oraclequantapi-0.0.1-SNAPSHOT.jar > app.log 2>&1 & + +# Check startup logs +tail -f app.log + +# Find process later +ps aux | grep oraclequantapi + +# Stop it +kill +``` + +### Step 5: Configure Firewall + +```bash +sudo firewall-cmd --add-port=8080/tcp --permanent +sudo firewall-cmd --reload +``` + +### Step 6: Verify Remotely + +```bash +curl "http://:8080/convert-measurements?input=aa" +``` + +Expected: +```json +{"packages": [1]} +``` + +--- + +## Logging + +Logs are written to `logs/pkc-api.log` using a rolling file appender with 7-day retention. Archived logs are named `logs/pkc-api.YYYY-MM-DD.log`. The logging level for the `com.oraclequantapi` package is set to `DEBUG` in `application.properties`. + +Console and file output use the format: +``` +yyyy-MM-dd HH:mm:ss [thread] LEVEL logger - message +``` + +--- + +## Changelog + +See [CHANGELOG.md](./CHANGELOG.md) for version history. + +## Version + +Current version: `0.0.1-SNAPSHOT` (see [version.txt](./version.txt)). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ab9f982 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +version: "3.8" +services: + oracle-db: + image: container-registry.oracle.com/database/express:21.3.0-xe + environment: + ORACLE_PWD: Oracle123 + ORACLE_CHARACTERSET: AL32UTF8 + ports: + - "1521:1521" + volumes: + - oracle-data:/opt/oracle/oradata + - ./docker-init:/opt/oracle/scripts/startup + healthcheck: + test: ["CMD", "/opt/oracle/checkDBStatus.sh"] + interval: 15s + timeout: 10s + retries: 20 + start_period: 120s + + pkc-api: + build: . + ports: + - "8080:8080" + environment: + SPRING_PROFILES_ACTIVE: docker + depends_on: + oracle-db: + condition: service_healthy + +volumes: + oracle-data: diff --git a/docker-init/01_create_user.sql b/docker-init/01_create_user.sql new file mode 100644 index 0000000..abd0bdd --- /dev/null +++ b/docker-init/01_create_user.sql @@ -0,0 +1,14 @@ +ALTER SESSION SET CONTAINER = XEPDB1; +BEGIN + EXECUTE IMMEDIATE 'CREATE USER pkc_user IDENTIFIED BY pkc_password'; + EXECUTE IMMEDIATE 'GRANT CONNECT, RESOURCE, DBA TO pkc_user'; + EXECUTE IMMEDIATE 'ALTER USER pkc_user QUOTA UNLIMITED ON USERS'; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE = -1920 THEN + NULL; + ELSE + RAISE; + END IF; +END; +/ diff --git a/logs/pkc-api.log b/logs/pkc-api.log new file mode 100644 index 0000000..919a38d --- /dev/null +++ b/logs/pkc-api.log @@ -0,0 +1,975 @@ +2026-05-21 09:33:43 [main] INFO c.o.o.OraclequantapiApplicationTests - Starting OraclequantapiApplicationTests using Java 17.0.18 with PID 20156 (started by OMEN in C:\Users\OMEN\OneDrive\Desktop\oraclequantapi) +2026-05-21 09:33:43 [main] INFO c.o.o.OraclequantapiApplicationTests - No active profile set, falling back to 1 default profile: "default" +2026-05-21 09:33:44 [main] WARN o.s.w.c.s.GenericWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} +2026-05-21 09:33:44 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2026-05-21 09:33:44 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Parameter 0 of constructor in com.oraclequantapi.oraclequantapi.service.HistoryService required a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' that could not be found. + + +Action: + +Consider defining a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' in your configuration. + +2026-05-21 09:33:44 [main] WARN o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] to prepare test instance [com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests@550e9be6] +java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@7c5d1d25 testClass = com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests, locations = [], classes = [com.oraclequantapi.oraclequantapi.OraclequantapiApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1224144a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@1e16c0aa, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@20bd8be5, org.springframework.boot.test.web.reactor.netty.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory$DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer@28194a50, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@5038d0b5, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@638ef7ed, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestAnnotation@365993b4], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180) + at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130) + at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:200) + at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:139) + at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) + at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:159) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:383) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:388) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:382) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:382) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:293) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:292) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:281) + at java.base/java.util.Optional.orElseGet(Optional.java:364) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:280) + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:27) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:112) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:111) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + 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:201) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:170) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:94) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:59) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:142) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:58) + 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.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39) + at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25) + at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithoutCancellationToken(LauncherAdapter.java:60) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:52) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136) + 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) +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1228) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1194) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1130) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:991) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) + at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:151) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) + at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1461) + at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:590) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:151) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:110) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) + ... 80 common frames omitted +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1708) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 106 common frames omitted +Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:2315) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1733) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 119 common frames omitted +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: zdaaaaaaaabaaaaaaaabaaaaaaaabbaa +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=34 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [34] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: abcdabcdab +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 7, 7] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: abbcc +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=6 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 6] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: a_ +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=0 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [0] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: aa +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [1] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: dz_a_aazzaaa +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=28 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [28, 1] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=40 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [40, 1] +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Converting input: abcdabcdab_ +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Non-letter '_' at position 10, emitting 0 +2026-05-21 09:33:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 7, 7, 0] +2026-05-21 09:34:08 [main] INFO c.o.o.OraclequantapiApplicationTests - Starting OraclequantapiApplicationTests using Java 17.0.18 with PID 572 (started by OMEN in C:\Users\OMEN\OneDrive\Desktop\oraclequantapi) +2026-05-21 09:34:08 [main] INFO c.o.o.OraclequantapiApplicationTests - No active profile set, falling back to 1 default profile: "default" +2026-05-21 09:34:09 [main] WARN o.s.w.c.s.GenericWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} +2026-05-21 09:34:09 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2026-05-21 09:34:09 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Parameter 0 of constructor in com.oraclequantapi.oraclequantapi.service.HistoryService required a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' that could not be found. + + +Action: + +Consider defining a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' in your configuration. + +2026-05-21 09:34:09 [main] WARN o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] to prepare test instance [com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests@3440e9cd] +java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@1642eeae testClass = com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests, locations = [], classes = [com.oraclequantapi.oraclequantapi.OraclequantapiApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1224144a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@1e16c0aa, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@20bd8be5, org.springframework.boot.test.web.reactor.netty.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory$DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer@28194a50, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@5038d0b5, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@638ef7ed, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestAnnotation@365993b4], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180) + at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130) + at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:200) + at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:139) + at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) + at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:159) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:383) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:388) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:382) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:382) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:293) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:292) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:281) + at java.base/java.util.Optional.orElseGet(Optional.java:364) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:280) + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:27) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:112) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:111) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + 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:201) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:170) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:94) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:59) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:142) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:58) + 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.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39) + at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25) + at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithoutCancellationToken(LauncherAdapter.java:60) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:52) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136) + 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) +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1228) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1194) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1130) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:991) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) + at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:151) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) + at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1461) + at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:590) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:151) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:110) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) + ... 80 common frames omitted +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1708) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 106 common frames omitted +Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:2315) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1733) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 119 common frames omitted +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: zdaaaaaaaabaaaaaaaabaaaaaaaabbaa +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=34 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [34] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: abcdabcdab +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 7, 7] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: abbcc +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=6 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 6] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: a_ +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=0 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [0] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: aa +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [1] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: dz_a_aazzaaa +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=28 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [28, 1] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=40 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [40, 1] +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Converting input: abcdabcdab_ +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Non-letter '_' at position 10, emitting 0 +2026-05-21 09:34:09 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 7, 7, 0] +2026-05-21 09:34:25 [main] INFO c.o.o.OraclequantapiApplicationTests - Starting OraclequantapiApplicationTests using Java 17.0.18 with PID 17960 (started by OMEN in C:\Users\OMEN\OneDrive\Desktop\oraclequantapi) +2026-05-21 09:34:25 [main] INFO c.o.o.OraclequantapiApplicationTests - No active profile set, falling back to 1 default profile: "default" +2026-05-21 09:34:26 [main] WARN o.s.w.c.s.GenericWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} +2026-05-21 09:34:26 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2026-05-21 09:34:26 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Parameter 0 of constructor in com.oraclequantapi.oraclequantapi.service.HistoryService required a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' that could not be found. + + +Action: + +Consider defining a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' in your configuration. + +2026-05-21 09:34:26 [main] WARN o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] to prepare test instance [com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests@51b77cdf] +java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@3ba3d4b6 testClass = com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests, locations = [], classes = [com.oraclequantapi.oraclequantapi.OraclequantapiApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@69ee81fc, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@29f7cefd, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@17503f6b, org.springframework.boot.test.web.reactor.netty.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory$DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer@50029372, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@6cc4cdb9, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@4c2bb6e0, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestAnnotation@365993b4], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180) + at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130) + at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:200) + at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:139) + at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) + at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:159) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:383) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:388) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:382) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:382) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:293) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:292) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:281) + at java.base/java.util.Optional.orElseGet(Optional.java:364) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:280) + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:27) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:112) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:111) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + 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:201) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:170) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:94) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:59) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:142) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:58) + 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.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39) + at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25) + at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithoutCancellationToken(LauncherAdapter.java:60) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:52) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136) + 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) +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1228) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1194) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1130) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:991) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) + at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:151) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) + at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1461) + at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:590) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:151) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:110) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) + ... 80 common frames omitted +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1708) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 106 common frames omitted +Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:2315) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1733) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 119 common frames omitted +2026-05-21 09:36:42 [main] INFO c.o.o.OraclequantapiApplicationTests - Starting OraclequantapiApplicationTests using Java 17.0.18 with PID 16672 (started by OMEN in C:\Users\OMEN\OneDrive\Desktop\oraclequantapi) +2026-05-21 09:36:42 [main] INFO c.o.o.OraclequantapiApplicationTests - No active profile set, falling back to 1 default profile: "default" +2026-05-21 09:36:43 [main] INFO c.o.o.OraclequantapiApplicationTests - Started OraclequantapiApplicationTests in 1.255 seconds (process running for 1.813) +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: zdaaaaaaaabaaaaaaaabaaaaaaaabbaa +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=34 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [34] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: abcdabcdab +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 7, 7] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: abbcc +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=6 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 6] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: a_ +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=0 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [0] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: aa +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [1] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: dz_a_aazzaaa +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=28 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [28, 1] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=40 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=1 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [40, 1] +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Converting input: abcdabcdab_ +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=2 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Package complete with total=7 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Non-letter '_' at position 10, emitting 0 +2026-05-21 09:36:44 [main] INFO c.o.o.service.SequenceService - Conversion result: [2, 7, 7, 0] +2026-05-21 10:15:42 [main] INFO c.o.o.OraclequantapiApplicationTests - Starting OraclequantapiApplicationTests using Java 17.0.18 with PID 6368 (started by OMEN in C:\Users\OMEN\OneDrive\Desktop\oraclequantapi) +2026-05-21 10:15:42 [main] INFO c.o.o.OraclequantapiApplicationTests - No active profile set, falling back to 1 default profile: "default" +2026-05-21 10:15:43 [main] WARN o.s.w.c.s.GenericWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} +2026-05-21 10:15:43 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2026-05-21 10:15:43 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Parameter 0 of constructor in com.oraclequantapi.oraclequantapi.service.HistoryService required a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' that could not be found. + + +Action: + +Consider defining a bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' in your configuration. + +2026-05-21 10:15:43 [main] WARN o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener] to prepare test instance [com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests@111d5c97] +java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@6bcb12e6 testClass = com.oraclequantapi.oraclequantapi.OraclequantapiApplicationTests, locations = [], classes = [com.oraclequantapi.oraclequantapi.OraclequantapiApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1224144a, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@1e16c0aa, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@20bd8be5, org.springframework.boot.test.web.reactor.netty.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory$DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer@28194a50, org.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory$OnFailureConditionReportContextCustomizer@5038d0b5, org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@638ef7ed, org.springframework.test.context.support.DynamicPropertiesContextCustomizer@0, org.springframework.boot.test.context.SpringBootTestAnnotation@365993b4], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180) + at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130) + at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:200) + at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:139) + at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) + at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:159) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:383) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:388) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:382) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) + at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) + at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) + at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) + at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) + at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) + at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) + at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) + at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:382) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:293) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:292) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:281) + at java.base/java.util.Optional.orElseGet(Optional.java:364) + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:280) + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:27) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:112) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:111) + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:128) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) + 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:160) + 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:146) + 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:144) + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:143) + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:100) + 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:201) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:170) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:94) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:59) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:142) + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:58) + 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.InterceptingLauncher.lambda$execute$1(InterceptingLauncher.java:39) + at org.junit.platform.launcher.core.ClasspathAlignmentCheckingLauncherInterceptor.intercept(ClasspathAlignmentCheckingLauncherInterceptor.java:25) + at org.junit.platform.launcher.core.InterceptingLauncher.execute(InterceptingLauncher.java:38) + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.executeWithoutCancellationToken(LauncherAdapter.java:60) + at org.apache.maven.surefire.junitplatform.LauncherAdapter.execute(LauncherAdapter.java:52) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:203) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:168) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:136) + 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) +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyController' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\controller\HistoryController.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1228) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1194) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1130) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:991) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) + at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:151) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) + at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) + at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1461) + at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:590) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:151) + at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:110) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) + at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) + ... 80 common frames omitted +Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'historyService' defined in file [C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes\com\oraclequantapi\oraclequantapi\service\HistoryService.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:804) + at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1395) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1708) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 106 common frames omitted +Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.oraclequantapi.oraclequantapi.repository.HistoryRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} + at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:2315) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1733) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1653) + at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:913) + at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) + ... 119 common frames omitted +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: zdaaaaaaaabaaaaaaaabaaaaaaaabbaa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: zdaaaaaaaabaaaaaaaabaaaaaaaabbaa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [34] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: abcdabcdab +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: abcdabcdab +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [2, 7, 7] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: abbcc +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: abbcc +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [2, 6] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: a_ +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: a_ +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [0] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: aa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: aa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [1] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: dz_a_aazzaaa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: dz_a_aazzaaa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [28, 1] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [40, 1] +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Creating sequence for input: abcdabcdab_ +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processing sequence: abcdabcdab_ +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Non-letter '_' at position 10, emitting 0 +2026-05-21 10:15:43 [main] INFO c.o.o.service.SequenceService - Processed sequence result: [2, 7, 7, 0] +2026-05-21 11:05:30 [main] INFO c.o.o.OraclequantapiApplication - Starting OraclequantapiApplication using Java 17.0.18 with PID 21768 (C:\Users\OMEN\OneDrive\Desktop\oraclequantapi\target\classes started by OMEN in C:\Users\OMEN\OneDrive\Desktop\oraclequantapi) +2026-05-21 11:05:30 [main] DEBUG c.o.o.OraclequantapiApplication - Running with Spring Boot v3.5.14, Spring v6.2.18 +2026-05-21 11:05:30 [main] INFO c.o.o.OraclequantapiApplication - No active profile set, falling back to 1 default profile: "default" +2026-05-21 11:05:30 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2026-05-21 11:05:30 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 24 ms. Found 1 JPA repository interface. +2026-05-21 11:05:30 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http) +2026-05-21 11:05:30 [main] INFO o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"] +2026-05-21 11:05:30 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2026-05-21 11:05:30 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.54] +2026-05-21 11:05:30 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2026-05-21 11:05:30 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 609 ms +2026-05-21 11:05:30 [main] INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default] +2026-05-21 11:05:30 [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.6.49.Final +2026-05-21 11:05:30 [main] INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled +2026-05-21 11:05:31 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer +2026-05-21 11:05:31 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... +2026-05-21 11:05:32 [main] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 12541, SQLState: 66000 +2026-05-21 11:05:32 [main] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=CruJ0ymbTu6AOH/atHeBVw==) +https://docs.oracle.com/error-help/db/ora-12541/ +2026-05-21 11:05:32 [main] WARN o.h.e.j.e.i.JdbcEnvironmentInitiator - HHH000342: Could not obtain connection to query metadata +org.hibernate.exception.GenericJDBCException: unable to obtain isolated JDBC connection [ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=CruJ0ymbTu6AOH/atHeBVw==) +https://docs.oracle.com/error-help/db/ora-12541/] [n/a] + at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:63) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94) + at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:116) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:334) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:129) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:81) + at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238) + at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215) + at org.hibernate.boot.model.relational.Database.(Database.java:45) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.getDatabase(InFlightMetadataCollectorImpl.java:226) + at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.(InFlightMetadataCollectorImpl.java:194) + at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:171) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1442) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1513) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:388) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:419) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:400) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:364) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1873) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1822) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:607) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:974) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) + at com.oraclequantapi.oraclequantapi.OraclequantapiApplication.main(OraclequantapiApplication.java:13) +Caused by: java.sql.SQLException: ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=CruJ0ymbTu6AOH/atHeBVw==) +https://docs.oracle.com/error-help/db/ora-12541/ + at oracle.jdbc.driver.T4CConnection.handleLogonNetException(T4CConnection.java:1853) + at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:1204) + at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:1189) + at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:106) + at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:887) + at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:694) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:144) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:370) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:207) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:488) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:576) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:97) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111) + at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:126) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:485) + at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:61) + ... 35 common frames omitted +Caused by: oracle.net.ns.NetException: ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=CruJ0ymbTu6AOH/atHeBVw==) +https://docs.oracle.com/error-help/db/ora-12541/ + at oracle.net.nt.TcpNTAdapter.handleEstablishSocketException(TcpNTAdapter.java:418) + at oracle.net.nt.TcpNTAdapter.establishSocket(TcpNTAdapter.java:350) + at oracle.net.nt.TcpNTAdapter.connect(TcpNTAdapter.java:228) + at oracle.net.nt.ConnOption.connect(ConnOption.java:346) + at oracle.net.nt.ConnStrategy.executeConnOption(ConnStrategy.java:1252) + at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:778) + at oracle.net.resolver.AddrResolution.resolveAndExecute(AddrResolution.java:718) + at oracle.net.ns.NSProtocol.establishConnection(NSProtocol.java:960) + at oracle.net.ns.NSProtocol.connect(NSProtocol.java:329) + at oracle.jdbc.driver.T4CConnection.connectNetworkSessionProtocol(T4CConnection.java:3684) + at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:1083) + ... 49 common frames omitted +Caused by: java.net.ConnectException: Connection refused: getsockopt + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:684) + at java.base/sun.nio.ch.SocketChannelImpl.finishTimedConnect(SocketChannelImpl.java:1158) + at java.base/sun.nio.ch.SocketChannelImpl.blockingConnect(SocketChannelImpl.java:1200) + at java.base/sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:98) + at oracle.net.nt.TimeoutSocketChannel.doConnect(TimeoutSocketChannel.java:291) + at oracle.net.nt.TimeoutSocketChannel.initializeSocketChannel(TimeoutSocketChannel.java:271) + at oracle.net.nt.TimeoutSocketChannel.connect(TimeoutSocketChannel.java:238) + at oracle.net.nt.TimeoutSocketChannel.(TimeoutSocketChannel.java:205) + at oracle.net.nt.TcpNTAdapter.establishSocket(TcpNTAdapter.java:339) + ... 58 common frames omitted +2026-05-21 11:05:32 [main] WARN org.hibernate.orm.deprecation - HHH90000025: OracleDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default) +2026-05-21 11:05:32 [main] INFO o.hibernate.orm.connections.pooling - HHH10001005: Database info: + Database JDBC URL [Connecting through datasource 'HikariDataSource (null)'] + Database driver: undefined/unknown + Database version: 19.0 + Autocommit mode: undefined/unknown + Isolation level: undefined/unknown + Minimum pool size: undefined/unknown + Maximum pool size: undefined/unknown +2026-05-21 11:05:32 [main] 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-05-21 11:05:32 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... +2026-05-21 11:05:33 [main] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 12541, SQLState: 66000 +2026-05-21 11:05:33 [main] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/ +2026-05-21 11:05:33 [main] ERROR o.s.o.j.LocalContainerEntityManagerFactoryBean - Failed to initialize JPA EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution [ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/] [n/a] +2026-05-21 11:05:33 [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution [ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/] [n/a] +2026-05-21 11:05:33 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2026-05-21 11:05:33 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2026-05-21 11:05:33 [main] ERROR o.s.boot.SpringApplication - Application run failed +org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution [ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/] [n/a] + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1826) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:607) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:974) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) + at com.oraclequantapi.oraclequantapi.OraclequantapiApplication.main(OraclequantapiApplication.java:13) +Caused by: jakarta.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution [ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/] [n/a] + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:431) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:400) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:364) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1873) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1822) + ... 15 common frames omitted +Caused by: org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution [ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/] [n/a] + at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:63) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108) + at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94) + at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:74) + at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:39) + at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:63) + at org.hibernate.tool.schema.extract.spi.ExtractionContext.getQueryResults(ExtractionContext.java:43) + at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:39) + at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.initializeSequences(DatabaseInformationImpl.java:66) + at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.(DatabaseInformationImpl.java:60) + at org.hibernate.tool.schema.internal.Helper.buildDatabaseInformation(Helper.java:185) + at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:93) + at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:280) + at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$5(SchemaManagementToolCoordinator.java:144) + at java.base/java.util.HashMap.forEach(HashMap.java:1421) + at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:141) + at org.hibernate.boot.internal.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:37) + at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:35) + at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:324) + at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:463) + at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1517) + at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) + at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:388) + at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:419) + ... 19 common frames omitted +Caused by: java.sql.SQLException: ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/ + at oracle.jdbc.driver.T4CConnection.handleLogonNetException(T4CConnection.java:1853) + at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:1204) + at oracle.jdbc.driver.PhysicalConnection.connect(PhysicalConnection.java:1189) + at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:106) + at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:887) + at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:694) + at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:144) + at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:370) + at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:207) + at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:488) + at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:576) + at com.zaxxer.hikari.pool.HikariPool.(HikariPool.java:97) + at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:111) + at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:126) + at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:485) + at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:46) + ... 39 common frames omitted +Caused by: oracle.net.ns.NetException: ORA-12541: Cannot connect. No listener at host localhost port 1521. (CONNECTION_ID=HS0uisn/SYuU8NWATsW0xQ==) +https://docs.oracle.com/error-help/db/ora-12541/ + at oracle.net.nt.TcpNTAdapter.handleEstablishSocketException(TcpNTAdapter.java:418) + at oracle.net.nt.TcpNTAdapter.establishSocket(TcpNTAdapter.java:350) + at oracle.net.nt.TcpNTAdapter.connect(TcpNTAdapter.java:228) + at oracle.net.nt.ConnOption.connect(ConnOption.java:346) + at oracle.net.nt.ConnStrategy.executeConnOption(ConnStrategy.java:1252) + at oracle.net.nt.ConnStrategy.execute(ConnStrategy.java:778) + at oracle.net.resolver.AddrResolution.resolveAndExecute(AddrResolution.java:718) + at oracle.net.ns.NSProtocol.establishConnection(NSProtocol.java:960) + at oracle.net.ns.NSProtocol.connect(NSProtocol.java:329) + at oracle.jdbc.driver.T4CConnection.connectNetworkSessionProtocol(T4CConnection.java:3684) + at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:1083) + ... 53 common frames omitted +Caused by: java.net.ConnectException: Connection refused: getsockopt + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:684) + at java.base/sun.nio.ch.SocketChannelImpl.finishTimedConnect(SocketChannelImpl.java:1158) + at java.base/sun.nio.ch.SocketChannelImpl.blockingConnect(SocketChannelImpl.java:1200) + at java.base/sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:98) + at oracle.net.nt.TimeoutSocketChannel.doConnect(TimeoutSocketChannel.java:291) + at oracle.net.nt.TimeoutSocketChannel.initializeSocketChannel(TimeoutSocketChannel.java:271) + at oracle.net.nt.TimeoutSocketChannel.connect(TimeoutSocketChannel.java:238) + at oracle.net.nt.TimeoutSocketChannel.(TimeoutSocketChannel.java:205) + at oracle.net.nt.TcpNTAdapter.establishSocket(TcpNTAdapter.java:339) + ... 62 common frames omitted diff --git a/pom.xml b/pom.xml index 20909d2..330be28 100644 --- a/pom.xml +++ b/pom.xml @@ -1,40 +1,58 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot spring-boot-starter-parent 3.5.14 - + com.oraclequantapi oraclequantapi 0.0.1-SNAPSHOT - - - - - - - - - - - - - - - + oraclequantapi + Package Measurement Conversion API 17 + org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + com.oracle.database.jdbc + ojdbc11 + runtime + + + + + org.projectlombok + lombok + true + + + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot spring-boot-starter-test @@ -44,9 +62,18 @@ + org.springframework.boot spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java b/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java index 5e28689..50413dd 100644 --- a/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java +++ b/src/main/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplication.java @@ -1,13 +1,24 @@ package com.oraclequantapi.oraclequantapi; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication +@Slf4j +/** + * Main starting point of the API. + * + * Spring Boot uses this class to start the web server, load the settings from + * application.properties, and create the controllers, services, and repositories. + */ public class OraclequantapiApplication { public static void main(String[] args) { + // These log lines make it easy to see in the console/file when the app starts. + log.info("Starting PKC API..."); SpringApplication.run(OraclequantapiApplication.class, args); + log.info("PKC API started successfully"); } } diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controller/HistoryController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controller/HistoryController.java new file mode 100644 index 0000000..ee7ccfa --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controller/HistoryController.java @@ -0,0 +1,90 @@ +package com.oraclequantapi.oraclequantapi.controller; + +import com.oraclequantapi.oraclequantapi.model.HistoryRecord; +import com.oraclequantapi.oraclequantapi.service.HistoryService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/history") +@RequiredArgsConstructor +@Slf4j +/** + * Web endpoints for viewing and editing saved conversion history. + * + * All URLs in this controller start with /history because of @RequestMapping. + */ +public class HistoryController { + + // Service that contains the actual history logic and database calls. + private final HistoryService historyService; + + /** + * Handles: GET /history + * Returns every saved conversion history record. + */ + @GetMapping + public ResponseEntity> getAll() { + log.info("GET /history called"); + return ResponseEntity.ok(historyService.getAll()); + } + + /** + * Handles: GET /history/{id} + * Returns one history record by its database id, or 404 if it does not exist. + */ + @GetMapping("/{id}") + public ResponseEntity getById(@PathVariable Long id) { + log.info("GET /history/{} called", id); + return historyService.getById(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + /** + * Handles: PUT /history/{id} + * Replaces the editable values on an existing history record. + */ + @PutMapping("/{id}") + public ResponseEntity update( + @PathVariable Long id, + @RequestBody HistoryRecord record) { + log.info("PUT /history/{} called", id); + return ResponseEntity.ok(historyService.update(id, record)); + } + + /** + * Handles: PATCH /history/{id} + * Updates only the fields sent in the request body, such as input or output. + */ + @PatchMapping("/{id}") + public ResponseEntity partialUpdate( + @PathVariable Long id, + @RequestBody Map updates) { + log.info("PATCH /history/{} called", id); + return ResponseEntity.ok(historyService.partialUpdate(id, updates)); + } + + /** + * Handles: DELETE /history + * Deletes all saved history rows. + */ + @DeleteMapping + public ResponseEntity deleteAll() { + log.info("DELETE /history called"); + historyService.deleteAll(); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controller/SequenceController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controller/SequenceController.java new file mode 100644 index 0000000..a478a04 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/controller/SequenceController.java @@ -0,0 +1,60 @@ +package com.oraclequantapi.oraclequantapi.controller; + +import com.oraclequantapi.oraclequantapi.dto.ConversionResponse; +import com.oraclequantapi.oraclequantapi.service.HistoryService; +import com.oraclequantapi.oraclequantapi.service.SequenceService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@Validated +@Slf4j +/** + * Web endpoint for converting one encoded input string into package numbers. + * + * A controller is the part of a Spring Boot app that receives HTTP requests. + */ +public class SequenceController { + + // Spring injects these services through the constructor created by Lombok. + private final SequenceService sequenceService; + private final HistoryService historyService; + + /** + * Handles: GET /convert-measurements?input=... + * + * It reads the input from the URL, converts it, stores a history row, and + * returns the conversion result as the HTTP response body. + */ + @GetMapping("/convert-measurements") + public ResponseEntity convert( + @RequestParam("input") + @NotBlank(message = "Input must not be blank") + @Pattern(regexp = "[a-z_]+", message = "Input must only contain lowercase letters a-z and underscores") + String input, + HttpServletRequest request) { + + log.info("GET /convert-measurements called with input={}", input); + + // Convert the encoded text into a list of package totals. + List packages = sequenceService.processSequence(sequenceService.getSequence(input)); + + // Save what happened so it can be reviewed later from the /history endpoints. + String ip = request.getRemoteAddr(); + historyService.save(input, packages.toString(), ip); + + log.info("Returning response: {}", packages); + return ResponseEntity.ok(new ConversionResponse(packages)); + } +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/dto/ConversionResponse.java b/src/main/java/com/oraclequantapi/oraclequantapi/dto/ConversionResponse.java new file mode 100644 index 0000000..ce3bf37 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/dto/ConversionResponse.java @@ -0,0 +1,17 @@ +package com.oraclequantapi.oraclequantapi.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@Data +@AllArgsConstructor +/** + * Response shape for returning converted package values. + * + * Wraps the package list in a JSON object like {"packages":[2,6]}. + */ +public class ConversionResponse { + private List packages; +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/exception/GlobalExceptionHandler.java b/src/main/java/com/oraclequantapi/oraclequantapi/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..b410bef --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/exception/GlobalExceptionHandler.java @@ -0,0 +1,40 @@ +package com.oraclequantapi.oraclequantapi.exception; + +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(ConstraintViolationException.class) + public ResponseEntity> handleValidation(ConstraintViolationException ex) { + log.warn("Validation error: {}", ex.getMessage()); + return ResponseEntity + .badRequest() + .body(Map.of("error", "Invalid input: " + ex.getMessage())); + } + + @ExceptionHandler(MissingServletRequestParameterException.class) + public ResponseEntity> handleMissingParam(MissingServletRequestParameterException ex) { + log.warn("Missing parameter: {}", ex.getMessage()); + return ResponseEntity + .badRequest() + .body(Map.of("error", "Missing required parameter: " + ex.getParameterName())); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGeneral(Exception ex) { + log.error("Unhandled exception", ex); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Internal server error")); + } +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/model/HistoryRecord.java b/src/main/java/com/oraclequantapi/oraclequantapi/model/HistoryRecord.java new file mode 100644 index 0000000..1a0ff6d --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/model/HistoryRecord.java @@ -0,0 +1,50 @@ +package com.oraclequantapi.oraclequantapi.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "conversion_history") +@Data +@NoArgsConstructor +@AllArgsConstructor +/** + * Database model for one saved conversion request. + * + * @Entity tells JPA this class is stored in a database table. Each field below + * becomes a column in the conversion_history table. + */ +public class HistoryRecord { + + // Primary key. The database sequence creates a new id for each row. + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "history_seq") + @SequenceGenerator(name = "history_seq", sequenceName = "history_seq", allocationSize = 1) + private Long id; + + // Date and time when the conversion request was saved. + @Column(nullable = false) + private LocalDateTime timestamp; + + // IP address of the client that called the conversion endpoint. + @Column(name = "source_ip_address", nullable = false) + private String sourceIpAddress; + + // Original encoded text received from the user. + @Column(nullable = false) + private String input; + + // Conversion result stored as text, for example "[2, 6]". + @Column(nullable = false) + private String output; +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/model/Sequence.java b/src/main/java/com/oraclequantapi/oraclequantapi/model/Sequence.java new file mode 100644 index 0000000..3ec4c55 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/model/Sequence.java @@ -0,0 +1,16 @@ +package com.oraclequantapi.oraclequantapi.model; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +/** + * Simple data object that carries the raw input string being converted. + * + * Lombok @Data creates getters/setters, and @AllArgsConstructor creates a + * constructor that accepts the input value. + */ +public class Sequence { + private String input; +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/repository/HistoryRepository.java b/src/main/java/com/oraclequantapi/oraclequantapi/repository/HistoryRepository.java new file mode 100644 index 0000000..80ce0f7 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/repository/HistoryRepository.java @@ -0,0 +1,15 @@ +package com.oraclequantapi.oraclequantapi.repository; + +import com.oraclequantapi.oraclequantapi.model.HistoryRecord; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +/** + * Database access layer for HistoryRecord rows. + * + * Extending JpaRepository gives this interface ready-made methods such as + * save, findAll, findById, and deleteAll without writing SQL by hand. + */ +public interface HistoryRepository extends JpaRepository { +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/service/HistoryService.java b/src/main/java/com/oraclequantapi/oraclequantapi/service/HistoryService.java new file mode 100644 index 0000000..524f602 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/service/HistoryService.java @@ -0,0 +1,107 @@ +package com.oraclequantapi.oraclequantapi.service; + +import com.oraclequantapi.oraclequantapi.model.HistoryRecord; +import com.oraclequantapi.oraclequantapi.repository.HistoryRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Slf4j +/** + * Business logic for conversion history. + * + * This service is the middle layer between web controllers and the database + * repository. Controllers call this class instead of talking to the database + * directly. + */ +public class HistoryService { + + // Repository is the database helper generated by Spring Data JPA. + private final HistoryRepository repository; + + /** + * Creates and saves one history row after a conversion request is handled. + */ + @Transactional + public HistoryRecord save(String input, String output, String sourceIpAddress) { + log.info("Saving history record for input={}, ip={}", input, sourceIpAddress); + HistoryRecord record = new HistoryRecord(); + record.setTimestamp(LocalDateTime.now()); + record.setInput(input); + record.setOutput(output); + record.setSourceIpAddress(sourceIpAddress); + return repository.save(record); + } + + /** + * Reads all saved conversion history rows. + * + * readOnly tells Spring this method only reads data and does not change it. + */ + @Transactional(readOnly = true) + public List getAll() { + log.info("Fetching all history records"); + return repository.findAll(); + } + + /** + * Reads one history row by id. + * + * Optional means the result may be empty if the id is not found. + */ + @Transactional(readOnly = true) + public Optional getById(Long id) { + log.info("Fetching history record by id={}", id); + return repository.findById(id); + } + + /** + * Updates the main editable fields of one history row. + */ + @Transactional + public HistoryRecord update(Long id, HistoryRecord updated) { + log.info("Updating history record id={}", id); + HistoryRecord existing = repository.findById(id) + .orElseThrow(() -> new RuntimeException("History record not found with id: " + id)); + existing.setInput(updated.getInput()); + existing.setOutput(updated.getOutput()); + return repository.save(existing); + } + + /** + * Updates only the fields provided by the request. + * + * For example, if the request body contains only "input", output is kept as it was. + */ + @Transactional + public HistoryRecord partialUpdate(Long id, Map updates) { + log.info("Partial updating history record id={}", id); + HistoryRecord existing = repository.findById(id) + .orElseThrow(() -> new RuntimeException("History record not found with id: " + id)); + updates.forEach((key, value) -> { + if ("input".equals(key)) { + existing.setInput((String) value); + } else if ("output".equals(key)) { + existing.setOutput((String) value); + } + }); + return repository.save(existing); + } + + /** + * Deletes every history row from the database. + */ + @Transactional + public void deleteAll() { + log.info("Deleting all history records"); + repository.deleteAll(); + } +} diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/service/SequenceService.java b/src/main/java/com/oraclequantapi/oraclequantapi/service/SequenceService.java new file mode 100644 index 0000000..9409c51 --- /dev/null +++ b/src/main/java/com/oraclequantapi/oraclequantapi/service/SequenceService.java @@ -0,0 +1,143 @@ +package com.oraclequantapi.oraclequantapi.service; + +import com.oraclequantapi.oraclequantapi.model.Sequence; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +/** + * Converts encoded letter strings into package totals. + * + * Encoding summary: + * - A letter at the start of a package says how many following characters to read. + * - a = 1, b = 2, c = 3, and so on. + * - z is special in the count area: each z adds 26, then the next letter adds more. + * - In the value area, underscore means 0 and z means 27. + */ +public class SequenceService { + + /** + * Wraps the raw input string in a Sequence object. + * + * This is small today, but it keeps the service method ready if more + * sequence information is added later. + */ + public Sequence getSequence(String input) { + log.info("Creating sequence for input: {}", input); + return new Sequence(input); + } + + /** + * Walks through the encoded text and builds the list of package totals. + * + * Example: input "abbcc" returns [2, 6]. + * - "a" means read 1 value: "b" = 2. + * - "b" means read 2 values: "cc" = 3 + 3 = 6. + */ + public List processSequence(Sequence sequence) { + String input = sequence.getInput(); + log.info("Processing sequence: {}", input); + List result = new ArrayList<>(); + int i = 0; + int len = input.length(); + + while (i < len) { + // If a package does not start with a letter, treat that position as value 0. + if (!isLetter(input.charAt(i))) { + log.info("Non-letter '{}' at position {}, emitting 0", input.charAt(i), i); + result.add(0); + i++; + continue; + } + + // First read how many following characters belong to this package. + int count = readCount(input, i); + int countChars = countCharsForCount(input, i); + i += countChars; + + int total = 0; + int valuesRead = 0; + + // Add the values inside this package until the requested count is reached. + while (valuesRead < count && i < len) { + char c = input.charAt(i); + total += (c == '_') ? 0 : valueOfValueChar(c); + i++; + valuesRead++; + } + + // Only add a package if the input contained enough value characters for it. + if (valuesRead == count) { + result.add(total); + } + } + + log.info("Processed sequence result: {}", result); + return result; + } + + /** + * This project only treats lowercase a-z as letters in the encoding. + */ + private boolean isLetter(char c) { + return c >= 'a' && c <= 'z'; + } + + /** + * Reads the package size at the current position. + * + * A normal letter gives its alphabet number. Leading z characters add 26 each. + */ + private int readCount(String input, int start) { + int count = 0; + int i = start; + while (i < input.length() && input.charAt(i) == 'z') { + count += 26; + i++; + } + if (i < input.length() && isLetter(input.charAt(i))) { + count += charValue(input.charAt(i)); + } + return count; + } + + /** + * Counts how many characters were used to describe the package size. + * + * The main loop needs this number so it can skip over the count characters + * and start reading the package values. + */ + private int countCharsForCount(String input, int start) { + int i = start; + while (i < input.length() && input.charAt(i) == 'z') { + i++; + } + if (i < input.length() && isLetter(input.charAt(i))) { + i++; + } + return i - start; + } + + /** + * Converts a count letter into a number: a = 1, b = 2, ... z = 26. + */ + private int charValue(char c) { + return c - 'a' + 1; + } + + /** + * Converts a package value letter into a number. + * + * In value positions, z is treated as 27 by the project rules. + */ + private int valueOfValueChar(char c) { + if (c == 'z') { + return 27; + } + return c - 'a' + 1; + } +} diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties new file mode 100644 index 0000000..7eb791b --- /dev/null +++ b/src/main/resources/application-docker.properties @@ -0,0 +1,10 @@ +spring.datasource.url=jdbc:oracle:thin:@oracle-db:1521/XEPDB1 +spring.datasource.username=pkc_user +spring.datasource.password=pkc_password +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver + +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect + +logging.level.com.oraclequantapi=DEBUG diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 99d0060..8b5bd3f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,16 @@ -spring.application.name=oraclequantapi +# Web server port for the REST API. +server.port=8080 + +# Oracle database connection used by Spring Data JPA. +spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1 +spring.datasource.username=pkc_user +spring.datasource.password=pkc_password +spring.datasource.driver-class-name=oracle.jdbc.OracleDriver + +# JPA/Hibernate settings. Hibernate maps Java entity classes to database tables. +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect + +# Shows detailed logs for this project's Java package. +logging.level.com.oraclequantapi=DEBUG diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..1d9dfc9 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,32 @@ + + + + + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + logs/pkc-api.log + + logs/pkc-api.%d{yyyy-MM-dd}.log + 7 + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + diff --git a/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java b/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java index 2de285b..99fdaf0 100644 --- a/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java +++ b/src/test/java/com/oraclequantapi/oraclequantapi/OraclequantapiApplicationTests.java @@ -4,10 +4,17 @@ import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest +/** + * Basic Spring Boot startup test. + * + * If this test passes, Spring can create the application context with the + * controllers, services, repositories, and configuration. + */ class OraclequantapiApplicationTests { @Test void contextLoads() { + // Empty on purpose: Spring Boot fails the test automatically if startup breaks. } } diff --git a/src/test/java/com/oraclequantapi/oraclequantapi/SequenceServiceTest.java b/src/test/java/com/oraclequantapi/oraclequantapi/SequenceServiceTest.java new file mode 100644 index 0000000..d4fa40b --- /dev/null +++ b/src/test/java/com/oraclequantapi/oraclequantapi/SequenceServiceTest.java @@ -0,0 +1,74 @@ +package com.oraclequantapi.oraclequantapi; + +import com.oraclequantapi.oraclequantapi.service.SequenceService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Unit tests for the sequence conversion rules. + * + * Each test sends an encoded string into SequenceService and checks that the + * returned package totals match the expected list. + */ +class SequenceServiceTest { + + private SequenceService service; + + // Create a fresh service before each test so tests do not share state. + @BeforeEach + void setUp() { + service = new SequenceService(); + } + + // "a" reads one following value, and "a" as a value is 1. + @Test + void testAa() { + assertEquals(List.of(1), service.processSequence(service.getSequence("aa"))); + } + + // First package: a -> one b value = 2. Second package: b -> two c values = 6. + @Test + void testAbbcc() { + assertEquals(List.of(2, 6), service.processSequence(service.getSequence("abbcc"))); + } + + // Covers z and underscore handling in the encoded input. + @Test + void testDz_a_aazzaaa() { + assertEquals(List.of(28, 1), service.processSequence(service.getSequence("dz_a_aazzaaa"))); + } + + // Underscore in a value position counts as 0. + @Test + void testA_() { + assertEquals(List.of(0), service.processSequence(service.getSequence("a_"))); + } + + // Checks multiple packages in one continuous input string. + @Test + void testAbcdabcdab() { + assertEquals(List.of(2, 7, 7), service.processSequence(service.getSequence("abcdabcdab"))); + } + + // A trailing underscore outside a complete package is returned as 0. + @Test + void testAbcdabcdab_() { + assertEquals(List.of(2, 7, 7, 0), service.processSequence(service.getSequence("abcdabcdab_"))); + } + + // Covers a package count larger than 26 by using leading z in the count area. + @Test + void testZdaaaaaaaabaaaaaaaabaaaaaaaabbaa() { + assertEquals(List.of(34), service.processSequence(service.getSequence("zdaaaaaaaabaaaaaaaabaaaaaaaabbaa"))); + } + + // Covers a long package where many underscores contribute zero to the total. + @Test + void testZa_a_a_a_a_a_a_a_a_a_a_a_a_azaaa() { + assertEquals(List.of(40, 1), service.processSequence(service.getSequence("za_a_a_a_a_a_a_a_a_a_a_a_a_azaaa"))); + } +} diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..cfefe08 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.0.1-SNAPSHOT