From eb1dbe047eca1efcd46526b6c9e66394031f8d0d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:13:05 +0000 Subject: [PATCH 1/7] Initial plan From 071641309f65b0d580fdb0e99245401a3b366c22 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:16:23 +0000 Subject: [PATCH 2/7] Update dependencies and config for PostgreSQL migration Co-authored-by: ArchILLtect <140122527+ArchILLtect@users.noreply.github.com> --- pom.xml | 10 ++--- .../persistence/SessionFactoryProvider.java | 14 +++---- src/main/resources/data.sql | 18 ++++----- src/main/resources/hibernate.cfg.xml | 20 ++++------ src/test/resources/cleandb.sql | 38 +++++++++---------- 5 files changed, 48 insertions(+), 52 deletions(-) diff --git a/pom.xml b/pom.xml index 9d5f05c..7120c6b 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 2.0.1.Final 6.2.5.Final 3.0.1-b11 - 8.4.0 + 42.7.4 3.13.0 3.2.5 @@ -164,11 +164,11 @@ ${javax.el.version} - + - com.mysql - mysql-connector-j - ${mysql.connector.version} + org.postgresql + postgresql + ${postgresql.connector.version} diff --git a/src/main/java/me/nickhanson/codeforge/persistence/SessionFactoryProvider.java b/src/main/java/me/nickhanson/codeforge/persistence/SessionFactoryProvider.java index 0f439ae..12984f3 100644 --- a/src/main/java/me/nickhanson/codeforge/persistence/SessionFactoryProvider.java +++ b/src/main/java/me/nickhanson/codeforge/persistence/SessionFactoryProvider.java @@ -60,11 +60,11 @@ private static SessionFactory buildSessionFactory() { url = explicitUrl; } else { String host = resolve("DB_HOST", "localhost"); - String port = resolve("DB_PORT", "3306"); + String port = resolve("DB_PORT", "5432"); String db = resolve("DB_NAME", "cf_test_db"); - url = "jdbc:mysql://" + host + ":" + port + "/" + db - + "?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC"; + url = "jdbc:postgresql://" + host + ":" + port + "/" + db + + "?ssl=true&sslmode=require"; } // Username: hibernate prop -> DB_USER -> default "root" @@ -91,14 +91,14 @@ private static SessionFactory buildSessionFactory() { // Dialect: can still be overridden if needed String dialect = resolve( "hibernate.dialect", - "org.hibernate.dialect.MySQL8Dialect" + "org.hibernate.dialect.PostgreSQLDialect" ); - // Ensure MySQL JDBC driver is present + // Ensure PostgreSQL JDBC driver is present try { - Class.forName("com.mysql.cj.jdbc.Driver"); + Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException e) { - throw new IllegalStateException("MySQL JDBC driver not found on classpath", e); + throw new IllegalStateException("PostgreSQL JDBC driver not found on classpath", e); } // Log *non-secret* connection info diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 540dacc..4487dd4 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -12,16 +12,16 @@ VALUES ('Median of Two Sorted Arrays', 'HARD', 'Find median of two sorted arrays.', 'Given two sorted arrays nums1 and nums2, return the median of the two sorted arrays.'); -- Seed submissions for a few challenges (dev only) -INSERT INTO SUBMISSIONS (CHALLENGE_ID, OUTCOME, CODE) +INSERT INTO SUBMISSIONS (CHALLENGE_ID, USER_ID, OUTCOME, CODE) VALUES - (1, 'CORRECT', 'int[] twoSum(int[] nums, int target) { /* ... */ }'), - (1, 'INCORRECT', '/* first attempt */'), - (2, 'ACCEPTABLE', 'boolean isValid(String s) { /* ... */ }'), - (3, 'SKIPPED', NULL); + (1, 'demo', 'CORRECT', 'int[] twoSum(int[] nums, int target) { /* ... */ }'), + (1, 'demo', 'INCORRECT', '/* first attempt */'), + (2, 'demo', 'ACCEPTABLE', 'boolean isValid(String s) { /* ... */ }'), + (3, 'demo', 'SKIPPED', NULL); -- Seed drill items for a few challenges (dev only) -INSERT INTO DRILL_ITEMS (CHALLENGE_ID, TIMES_SEEN, STREAK, NEXT_DUE_AT) +INSERT INTO DRILL_ITEMS (CHALLENGE_ID, USER_ID, TIMES_SEEN, STREAK, NEXT_DUE_AT) VALUES - (1, 2, 1, NULL), - (2, 1, 0, NULL), - (3, 3, 2, NULL); \ No newline at end of file + (1, 'demo', 2, 1, NULL), + (2, 'demo', 1, 0, NULL), + (3, 'demo', 3, 2, NULL); \ No newline at end of file diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml index 1222aba..27e37f7 100644 --- a/src/main/resources/hibernate.cfg.xml +++ b/src/main/resources/hibernate.cfg.xml @@ -4,25 +4,21 @@ "https://hibernate.org/dtd/hibernate-configuration-3.0.dtd"> - - com.mysql.cj.jdbc.Driver - + + org.postgresql.Driver + - jdbc:mysql://${DB_HOST}:3306/${DB_NAME} - ?useSSL=false - &allowPublicKeyRetrieval=true - &serverTimezone=UTC - &useUnicode=true - &characterEncoding=utf8mb4 - &connectionCollation=utf8mb4_unicode_ci + jdbc:postgresql://${DB_HOST}:5432/${DB_NAME} + ?ssl=true + &sslmode=require ${DB_USER} ${DB_PASS} - - org.hibernate.dialect.MySQL8Dialect + + org.hibernate.dialect.PostgreSQLDialect true diff --git a/src/test/resources/cleandb.sql b/src/test/resources/cleandb.sql index c6aacf5..8a0de27 100644 --- a/src/test/resources/cleandb.sql +++ b/src/test/resources/cleandb.sql @@ -1,42 +1,38 @@ -- Purpose: Reset schema and seed sample data for local/dev testing --- MySQL version +-- PostgreSQL version --- Disable FK checks for dropping -SET FOREIGN_KEY_CHECKS = 0; - -DROP TABLE IF EXISTS submissions; -DROP TABLE IF EXISTS drill_items; -DROP TABLE IF EXISTS challenges; - -SET FOREIGN_KEY_CHECKS = 1; +-- Drop tables (CASCADE handles foreign keys automatically) +DROP TABLE IF EXISTS submissions CASCADE; +DROP TABLE IF EXISTS drill_items CASCADE; +DROP TABLE IF EXISTS challenges CASCADE; -- ------------------------------------------ -- Recreate tables -- ------------------------------------------ CREATE TABLE challenges ( - id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, title VARCHAR(255) NOT NULL, blurb TEXT, prompt_md TEXT, expected_answer TEXT, - difficulty ENUM('EASY', 'MEDIUM', 'HARD') NOT NULL, + difficulty VARCHAR(20) NOT NULL CHECK (difficulty IN ('EASY', 'MEDIUM', 'HARD')), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - UNIQUE KEY uk_challenges_title (title) + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT uk_challenges_title UNIQUE (title) ); CREATE TABLE drill_items ( - id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, challenge_id BIGINT NOT NULL, user_id VARCHAR(64) NOT NULL, -- MVP: string-based user identifier (e.g., 'demo' or Cognito sub) times_seen INT NOT NULL DEFAULT 0, streak INT NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, next_due_at TIMESTAMP NULL DEFAULT NULL, version BIGINT NOT NULL DEFAULT 0, - UNIQUE KEY uk_drill_items_user_challenge (user_id, challenge_id), + CONSTRAINT uk_drill_items_user_challenge UNIQUE (user_id, challenge_id), CONSTRAINT fk_drill_items_challenge FOREIGN KEY (challenge_id) REFERENCES challenges(id) @@ -45,13 +41,13 @@ CREATE TABLE drill_items ( ); CREATE TABLE submissions ( - id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, challenge_id BIGINT NOT NULL, user_id VARCHAR(64) NOT NULL, -- MVP: string-based user identifier (e.g., 'demo' or Cognito sub) - outcome ENUM('CORRECT', 'INCORRECT', 'ACCEPTABLE', 'SKIPPED') NOT NULL, + outcome VARCHAR(20) NOT NULL CHECK (outcome IN ('CORRECT', 'INCORRECT', 'ACCEPTABLE', 'SKIPPED')), code TEXT, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_submissions_challenge FOREIGN KEY (challenge_id) REFERENCES challenges(id) @@ -68,6 +64,10 @@ CREATE INDEX idx_submissions_user_id ON submissions (user_id); -- Seed sample data -- ------------------------------------------ +-- ------------------------------------------ +-- Seed sample data +-- ------------------------------------------ + INSERT INTO challenges (title, blurb, prompt_md, expected_answer, difficulty) VALUES ('Array Pivot', 'Find pivot index in an array', 'Prompt\nGiven an array...', 'pivotIndex', 'EASY'), ('Linked Reversal', 'Reverse a singly linked list', 'Prompt\nImplement reverse...', 'reverseList', 'EASY'), From 5e05f6e077d440eb550605e837530fb4219d2805 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:18:56 +0000 Subject: [PATCH 3/7] Update documentation and test config for PostgreSQL Co-authored-by: ArchILLtect <140122527+ArchILLtect@users.noreply.github.com> --- .../java/code-forge/logs/cognitoexercise.log | 85 ++++++++++++ README.md | 4 +- docs/deployment.md | 121 ++++++++---------- .../codeforge/testutil/Database.java | 2 +- 4 files changed, 144 insertions(+), 68 deletions(-) create mode 100644 C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log diff --git a/C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log b/C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log new file mode 100644 index 0000000..ecdd450 --- /dev/null +++ b/C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log @@ -0,0 +1,85 @@ +[ERROR] 2026-02-13 02:17:02.535 [main] PropertiesLoader - ERROR: File/path not found. +java.lang.NullPointerException: inStream parameter is null + at java.base/java.util.Objects.requireNonNull(Objects.java:235) ~[?:?] + at java.base/java.util.Properties.load(Properties.java:407) ~[?:?] + at me.nickhanson.codeforge.config.PropertiesLoader.loadProperties(PropertiesLoader.java:30) ~[classes/:?] + at me.nickhanson.codeforge.config.LocalConfig.load(LocalConfig.java:19) ~[classes/:?] + at me.nickhanson.codeforge.config.LocalConfig.get(LocalConfig.java:30) ~[classes/:?] + at me.nickhanson.codeforge.persistence.SessionFactoryProvider.resolve(SessionFactoryProvider.java:43) ~[classes/:?] + at me.nickhanson.codeforge.persistence.SessionFactoryProvider.buildSessionFactory(SessionFactoryProvider.java:56) ~[classes/:?] + at me.nickhanson.codeforge.persistence.SessionFactoryProvider.(SessionFactoryProvider.java:23) ~[classes/:?] + at me.nickhanson.codeforge.persistence.GenericDao.(GenericDao.java:33) ~[classes/:?] + at me.nickhanson.codeforge.persistence.ChallengeDao.(ChallengeDao.java:25) ~[classes/:?] + at me.nickhanson.codeforge.persistence.ChallengeDaoTest.(ChallengeDaoTest.java:17) ~[test-classes/:?] + at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] + at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] + at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] + at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500) ~[?:?] + at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) ~[?:?] + at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:553) ~[junit-platform-commons-1.10.3.jar:1.10.3] + at org.junit.jupiter.engine.execution.ConstructorInvocation.proceed(ConstructorInvocation.java:56) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:74) ~[junit-jupiter-api-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:62) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:364) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:311) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:287) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:279) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at java.base/java.util.Optional.orElseGet(Optional.java:364) ~[?:?] + at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:278) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[?:?] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[?:?] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[junit-platform-engine-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) ~[junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) ~[junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) ~[junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) ~[junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) [junit-platform-launcher-1.10.3.jar:1.10.3] + at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) [surefire-junit-platform-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) [surefire-junit-platform-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) [surefire-junit-platform-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:122) [surefire-junit-platform-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) [surefire-booter-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) [surefire-booter-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.2.5.jar:3.2.5] + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.2.5.jar:3.2.5] diff --git a/README.md b/README.md index 632ab44..501d3e8 100644 --- a/README.md +++ b/README.md @@ -128,10 +128,10 @@ CodeForge’s goal is to provide a *simpler, clarity-first alternative* to platf - Lightweight CSS (“CodeForge UI”) without a large framework - ### Database - - MySQL (local/dev tests and prod) + - PostgreSQL (Neon for production, local for dev/tests) - Test DB reset via `DbReset` + `cleandb.sql` - Seed data managed in `src/test/resources/cleandb.sql` (predictable schema) - - **AWS RDS** — Cloud-hosted DB for deployment + - **Neon (Postgres)** — Cloud-hosted serverless DB for deployment - ### Authentication & Security - Amazon Cognito Hosted UI (servlet-based flow) diff --git a/docs/deployment.md b/docs/deployment.md index 0cf4db1..82b0dd4 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -3,8 +3,8 @@ This project runs as a WAR on Tomcat 9 (Jakarta Servlet API). The persistence layer uses Hibernate directly (no Spring). For MVP, schema is managed by Hibernate auto‑DDL; Flyway is a post‑MVP task. ## Environments -- Dev/Test: H2 in‑memory DB via `src/main/resources/hibernate.cfg.xml` -- Prod (Week 8): AWS RDS (PostgreSQL or MySQL) +- Dev/Test: PostgreSQL (local or Docker) +- Prod: Neon (serverless PostgreSQL) ## Required runtime configuration - Cognito secret: provided by environment or JVM property @@ -18,23 +18,18 @@ This project runs as a WAR on Tomcat 9 (Jakarta Servlet API). The persistence la ### Dev/Test (default) - `src/main/resources/hibernate.cfg.xml` points to H2 and sets `hbm2ddl.auto=update`. -### Production (RDS) -Use either approach: -1) Tomcat JNDI DataSource (recommended) - - Define a JNDI resource in Tomcat `conf/context.xml` or the webapp context `META-INF/context.xml`: - ```xml - - ``` - - Update your Hibernate configuration to use JNDI lookup (optional enhancement), or provide a prod `hibernate.cfg.xml` packaged for deployment. - -2) Prod `hibernate.cfg.xml` - - Build a production variant of `hibernate.cfg.xml` with your RDS JDBC URL, user, and password. - - First deploy: set `update` - - After verification: change to `validate` and redeploy +### Production (Neon PostgreSQL) +Use environment variables or system properties: +- `DB_HOST`: Neon PostgreSQL endpoint (e.g., `ep-xyz.us-east-1.aws.neon.tech`) +- `DB_PORT`: `5432` (default PostgreSQL port) +- `DB_NAME`: Database name +- `DB_USER`: Database username +- `DB_PASS`: Database password + +Connection string format: +``` +jdbc:postgresql://:5432/?ssl=true&sslmode=require +``` ## Balanced Approach (MVP) - Phase 1 (first deploy): allow Hibernate to create/update tables with `hbm2ddl.auto=update` @@ -58,13 +53,12 @@ cmd /c 'cd /d "C:\Users\nickh\Documents\My Projects\Java\code-forge" && mvn -q - - Or add to Tomcat service/`setenv` as `-DCOGNITO_CLIENT_SECRET=your_secret` - Start Tomcat and open `http://localhost:8080/codeforge/` -## RDS specifics -- Create DB (PostgreSQL/MySQL), note endpoint, user, password -- Security groups: allow inbound from your app host -- JDBC URL examples: - - Postgres: `jdbc:postgresql://:5432/` - - MySQL: `jdbc:mysql://:3306/?useSSL=true&requireSSL=true` -- On first deploy, keep DDL `update`; after verifying tables (`challenges`, `submissions`, `drill_items`), flip to `validate` +## RDS/Neon specifics +- Neon provides serverless PostgreSQL with automatic scaling +- Security: Neon requires SSL (`ssl=true&sslmode=require`) +- JDBC URL example: + - Postgres/Neon: `jdbc:postgresql://:5432/?ssl=true&sslmode=require` +- On first deploy, Hibernate can auto-create schema with `hbm2ddl.auto=update`; after verifying tables (`challenges`, `submissions`, `drill_items`), consider switching to `validate` ## QuoteService notes - `QuoteService` loads `application.properties` from the classpath and uses `HttpClient` for outbound calls @@ -90,48 +84,41 @@ For production (AWS RDS), override datasource and JPA properties with environmen --- -## 1) Provision AWS RDS - -- Choose engine/version (e.g., PostgreSQL 15.x or MySQL 8.x). -- Create database (DB name, username, password). -- Configure security group rules to allow inbound from your app host (e.g., Elastic Beanstalk instance SG). -- Note the JDBC endpoint: `host:port/dbname`. +## 1) Provision Neon Database -## 2) Configure application (first deploy) +- Create a new project in Neon (https://neon.tech) +- Note the connection details: host, database name, username, password +- Neon automatically provides SSL-enabled PostgreSQL endpoints -Set the following environment variables in your hosting environment (Elastic Beanstalk, ECS, EC2, etc.), or for an one‑off local test run: +## 2) Configure application (Render deployment) -- `SPRING_DATASOURCE_URL` - - PostgreSQL: `jdbc:postgresql://:/?sslmode=require` - - MySQL: `jdbc:mysql://:/?allowPublicKeyRetrieval=true&useSSL=true&requireSSL=true&useUnicode=true&characterEncoding=utf8` -- `SPRING_DATASOURCE_USERNAME` -- `SPRING_DATASOURCE_PASSWORD` -- `SPRING_JPA_HIBERNATE_DDL_AUTO=update` (first deploy only — lets Hibernate create missing tables/columns) +Set the following environment variables in Render: -Example one‑shot local run on Windows cmd: +- `DB_HOST`: Neon endpoint (e.g., `ep-xyz.us-east-1.aws.neon.tech`) +- `DB_PORT`: `5432` +- `DB_NAME`: Database name +- `DB_USER`: Database username +- `DB_PASS`: Database password -```bat -cmd /c 'set "SPRING_DATASOURCE_URL=jdbc:postgresql://mydb.abcdefg.us-east-1.rds.amazonaws.com:5432/codeforge?sslmode=require" && set "SPRING_DATASOURCE_USERNAME=appuser" && set "SPRING_DATASOURCE_PASSWORD=secret" && set "SPRING_JPA_HIBERNATE_DDL_AUTO=update" && mvn -q spring-boot:run' +The application will build the JDBC URL automatically with SSL enabled: +``` +jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}?ssl=true&sslmode=require ``` - -Notes -- The app already externalizes server port via `server.port=${PORT:5000}`. -- Keep test/dev profiles pointed at H2; only prod uses RDS overrides. ## 3) Deploy and verify -- Deploy the app to your AWS environment with the env vars above. -- Verify health: - - `GET /actuator/health` → `UP` +- Deploy the app to Render with the environment variables above. +- Hibernate will auto-create the schema on first startup (using entity annotations). - Verify schema: - - Check RDS tables exist: `challenges`, `submissions`, `drill_items`, including `drill_items.version` (added in Issue 38 via `@Version`). + - Connect to Neon and check that tables exist: `challenges`, `submissions`, `drill_items`, including `drill_items.version` (added via `@Version`). - Smoke test the app (e.g., run a Drill flow to insert data). -## 4) Flip ddl-auto to validate +## 4) Schema management notes -Once the schema looks correct in RDS: -- Change environment variable: `SPRING_JPA_HIBERNATE_DDL_AUTO=validate` -- Redeploy the app. Hibernate will now validate the schema at startup and fail fast if it drifts, but it will no longer apply changes automatically. +- Hibernate uses entity annotations to create/validate schema +- First deploy: Hibernate will auto-create tables based on `@Entity` classes +- After verification: you can set `hibernate.hbm2ddl.auto=validate` to prevent auto-changes +- Future: consider Flyway for versioned migrations (post-MVP) ## 5) Post‑MVP: Adopt Flyway migrations @@ -147,16 +134,20 @@ After MVP deployment stabilizes: ## 6) Troubleshooting - `relation/table not found` at startup: - - You likely deployed with `ddl-auto=validate` before the schema existed; switch back to `update` for the first run. -- Permission errors creating tables: - - Ensure the RDS user has `CREATE`/`ALTER` permissions. + - Ensure Hibernate can create tables (check DB user permissions). - Driver/URL errors: - - Confirm the correct JDBC driver is on the classpath (Spring Boot starters include both Postgres/MySQL when added) and that the JDBC URL is correct for your engine. + - Confirm PostgreSQL JDBC driver is in dependencies and JDBC URL is correct. - Connection timeouts: - - Check RDS SG rules, VPC networking, and that your app host can reach the RDS endpoint. - -## 7) Quick rollback plan - -- Keep `ddl-auto` in an env var so you can temporarily switch back to `update` if a small non‑destructive patch is needed. -- Prefer to schedule structural changes; adopt Flyway promptly post‑MVP for safer, versioned changes. + - Verify DB_HOST, DB_PORT, and that Neon endpoint is accessible from Render. + - Check that SSL is enabled (`ssl=true&sslmode=require`). + +## 7) Migration from AWS RDS MySQL + +If migrating from existing MySQL database: +1. Export data from MySQL using `mysqldump` or similar +2. Convert MySQL syntax to PostgreSQL (AUTO_INCREMENT → SERIAL, ENUM → VARCHAR/CHECK, etc.) +3. Import into Neon using `psql` or database client +4. Update Render environment variables to point to Neon +5. Deploy and verify +6. After successful verification, delete AWS RDS instance diff --git a/src/test/java/me/nickhanson/codeforge/testutil/Database.java b/src/test/java/me/nickhanson/codeforge/testutil/Database.java index 0cb0220..201626f 100644 --- a/src/test/java/me/nickhanson/codeforge/testutil/Database.java +++ b/src/test/java/me/nickhanson/codeforge/testutil/Database.java @@ -50,7 +50,7 @@ public void connect() throws Exception { try { Class.forName(properties.getProperty("hibernate.connection.driver_class")); } catch (ClassNotFoundException e) { - throw new Exception("MySQL Driver not found", e); + throw new Exception("Database Driver not found", e); } String url = properties.getProperty("hibernate.connection.url"); From 4548b3de12dba33a1b82a9a7d3fcf41f0cb4a00e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:19:19 +0000 Subject: [PATCH 4/7] Remove accidentally committed log file --- .../java/code-forge/logs/cognitoexercise.log | 85 ------------------- 1 file changed, 85 deletions(-) delete mode 100644 C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log diff --git a/C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log b/C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log deleted file mode 100644 index ecdd450..0000000 --- a/C:/Users/nickh/Documents/My Projects/java/code-forge/logs/cognitoexercise.log +++ /dev/null @@ -1,85 +0,0 @@ -[ERROR] 2026-02-13 02:17:02.535 [main] PropertiesLoader - ERROR: File/path not found. -java.lang.NullPointerException: inStream parameter is null - at java.base/java.util.Objects.requireNonNull(Objects.java:235) ~[?:?] - at java.base/java.util.Properties.load(Properties.java:407) ~[?:?] - at me.nickhanson.codeforge.config.PropertiesLoader.loadProperties(PropertiesLoader.java:30) ~[classes/:?] - at me.nickhanson.codeforge.config.LocalConfig.load(LocalConfig.java:19) ~[classes/:?] - at me.nickhanson.codeforge.config.LocalConfig.get(LocalConfig.java:30) ~[classes/:?] - at me.nickhanson.codeforge.persistence.SessionFactoryProvider.resolve(SessionFactoryProvider.java:43) ~[classes/:?] - at me.nickhanson.codeforge.persistence.SessionFactoryProvider.buildSessionFactory(SessionFactoryProvider.java:56) ~[classes/:?] - at me.nickhanson.codeforge.persistence.SessionFactoryProvider.(SessionFactoryProvider.java:23) ~[classes/:?] - at me.nickhanson.codeforge.persistence.GenericDao.(GenericDao.java:33) ~[classes/:?] - at me.nickhanson.codeforge.persistence.ChallengeDao.(ChallengeDao.java:25) ~[classes/:?] - at me.nickhanson.codeforge.persistence.ChallengeDaoTest.(ChallengeDaoTest.java:17) ~[test-classes/:?] - at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] - at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] - at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] - at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500) ~[?:?] - at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) ~[?:?] - at org.junit.platform.commons.util.ReflectionUtils.newInstance(ReflectionUtils.java:553) ~[junit-platform-commons-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.execution.ConstructorInvocation.proceed(ConstructorInvocation.java:56) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:74) ~[junit-jupiter-api-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:62) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:364) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:311) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:287) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:279) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at java.base/java.util.Optional.orElseGet(Optional.java:364) ~[?:?] - at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:278) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) ~[junit-jupiter-engine-5.10.3.jar:5.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[?:?] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[?:?] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[junit-platform-engine-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:198) ~[junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:169) ~[junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:93) ~[junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:58) ~[junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:141) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:57) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:103) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:85) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.junit.platform.launcher.core.DelegatingLauncher.execute(DelegatingLauncher.java:47) [junit-platform-launcher-1.10.3.jar:1.10.3] - at org.apache.maven.surefire.junitplatform.LazyLauncher.execute(LazyLauncher.java:56) [surefire-junit-platform-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.execute(JUnitPlatformProvider.java:184) [surefire-junit-platform-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:148) [surefire-junit-platform-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:122) [surefire-junit-platform-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) [surefire-booter-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) [surefire-booter-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) [surefire-booter-3.2.5.jar:3.2.5] - at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) [surefire-booter-3.2.5.jar:3.2.5] From 8e8f7ad44692abcd26d707425d9edfaf1b51001b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:20:11 +0000 Subject: [PATCH 5/7] Add test config example and verify build Co-authored-by: ArchILLtect <140122527+ArchILLtect@users.noreply.github.com> --- src/test/resources/test-db.properties.example | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/test/resources/test-db.properties.example diff --git a/src/test/resources/test-db.properties.example b/src/test/resources/test-db.properties.example new file mode 100644 index 0000000..90c44f6 --- /dev/null +++ b/src/test/resources/test-db.properties.example @@ -0,0 +1,9 @@ +# PostgreSQL connection settings for local testing +# Copy this file to test-db.properties and update with your local PostgreSQL credentials +# test-db.properties is git-ignored to prevent committing secrets + +hibernate.connection.driver_class=org.postgresql.Driver +hibernate.connection.url=jdbc:postgresql://localhost:5432/cf_test_db?ssl=false +hibernate.connection.username=postgres +hibernate.connection.password=your_password_here +hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect From df16625c69b0bec80803c9b1986926943d4bf9e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:22:32 +0000 Subject: [PATCH 6/7] Fix duplicate comment in cleandb.sql Co-authored-by: ArchILLtect <140122527+ArchILLtect@users.noreply.github.com> --- src/test/resources/cleandb.sql | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/test/resources/cleandb.sql b/src/test/resources/cleandb.sql index 8a0de27..96a347e 100644 --- a/src/test/resources/cleandb.sql +++ b/src/test/resources/cleandb.sql @@ -64,10 +64,6 @@ CREATE INDEX idx_submissions_user_id ON submissions (user_id); -- Seed sample data -- ------------------------------------------ --- ------------------------------------------ --- Seed sample data --- ------------------------------------------ - INSERT INTO challenges (title, blurb, prompt_md, expected_answer, difficulty) VALUES ('Array Pivot', 'Find pivot index in an array', 'Prompt\nGiven an array...', 'pivotIndex', 'EASY'), ('Linked Reversal', 'Reverse a singly linked list', 'Prompt\nImplement reverse...', 'reverseList', 'EASY'), From 7d7bf82c4ec0af72af207617740c72cd41b3acc7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:25:33 +0000 Subject: [PATCH 7/7] Security fix: Update PostgreSQL JDBC driver to 42.7.7 to patch authentication vulnerability Co-authored-by: ArchILLtect <140122527+ArchILLtect@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7120c6b..670ffe3 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 2.0.1.Final 6.2.5.Final 3.0.1-b11 - 42.7.4 + 42.7.7 3.13.0 3.2.5