feat(task): adopt JPA feature boundaries
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# Test Evidence: Role-correct Task dashboard query
|
||||
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `AUTH-003`–`AUTH-005`, `AUTH-009`, `TSK-001`, `TSK-002`, `TSK-004`, `PRJ-016`
|
||||
- **Scenario IDs:** `I1-UI-03`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.service.TaskDashboardServiceTest`
|
||||
- **Implementation commit:** `pending`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
The public Task dashboard service reports blocked Tasks only for a Mentor's active owned Projects. For an Intern, it excludes former/completed memberships, counts current assigned Tasks, and returns at most five priority Tasks ordered by due date with null dates last and Task ID as the stable tie-breaker.
|
||||
|
||||
## Test method
|
||||
|
||||
Two focused Mockito tests provide Project service DTOs and verify the Task service result. The repository remains mocked so the test isolates role/project/member filtering and the Task-owned dashboard DTO boundary; PostgreSQL query ordering is verified by the affected integration suite.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
A Mentor with one active and one planned Project receives the active Project's four blocked Tasks only. An Intern with one current active membership, one former membership, and one completed Project receives six assigned Tasks and the due-first Task from the current Project.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskDashboardServiceTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] TaskDashboardServiceTest.java:[34,13] cannot find symbol
|
||||
symbol: class TaskDashboardService
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskDashboardServiceTest test
|
||||
```
|
||||
|
||||
Run with approved sandbox escalation for Mockito Java 25 self-attach.
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## Affected suite
|
||||
|
||||
**Command and result**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
||||
./mvnw -Dtest=TaskPersistenceStructureTest,TaskDomainRulesTest,TaskControllerTest,TaskQueryServiceTest,TaskDashboardServiceTest,TaskMutationBoundaryTest,TaskCreationIntegrationTest test
|
||||
|
||||
[INFO] Tests run: 51, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This test does not prove the shared dashboard controller/template, which belongs to `work/reports-ui`. PostgreSQL ordering, soft-delete filtering, and repository query syntax remain integration-test concerns.
|
||||
@@ -0,0 +1,77 @@
|
||||
# Test Evidence: Task mutation authorization and locking boundary
|
||||
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `AUTH-011`, `TSK-003`, `TSK-007`, `TSK-012`, `TSK-018`
|
||||
- **Scenario IDs:** `I1-TSK-01`, `I1-TSK-03`, `I1-TSK-04`, `AC-AUTH-010`, `AC-TSK-003`, `AC-TSK-006`, `AC-TSK-010`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.service.TaskMutationBoundaryTest`
|
||||
- **Implementation commit:** `pending`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Every Task create/status/comment mutation first asks the concrete Project service for a current authorization context while holding the Project row lock. Status and comment mutations then load the Task with `PESSIMISTIC_WRITE` before checking or changing Task state.
|
||||
|
||||
## Test method
|
||||
|
||||
Three focused Mockito tests verify call order for create, status, and comment. They prove the Project mutation context precedes the Task write, the unlocked Project query is not used for create, and status/comment use the locked Task lookup before mutation. `TaskPersistenceStructureTest` separately inspects the real repository method's lock annotation, while the PostgreSQL workflow suite executes the query.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
Create calls `ProjectService.taskMutationContext(5, 10)` before saving. Status and comment call that same Project boundary, then `TaskRepository.findLockedByIdAndProjectIdAndDeletedAtIsNull(25, 10)`, before changing status or appending the comment. The Project service joins the outer Task transaction, so both locks remain through commit or rollback.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskMutationBoundaryTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] constructor TaskService ... cannot be applied to given types
|
||||
required: TaskRepository,TaskCommentRepository,ProjectQueryService,CalendarApplicationService,Clock
|
||||
found: TaskRepository,TaskCommentRepository,ProjectQueryService,ProjectService,CalendarApplicationService,Clock
|
||||
[ERROR] cannot find symbol
|
||||
symbol: method findLockedByIdAndProjectIdAndDeletedAtIsNull(long,long)
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskMutationBoundaryTest test
|
||||
```
|
||||
|
||||
Run with approved sandbox escalation for Mockito Java 25 self-attach.
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## Affected suite
|
||||
|
||||
**Command and result**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
||||
./mvnw -Dtest=TaskPersistenceStructureTest,TaskDomainRulesTest,TaskControllerTest,TaskQueryServiceTest,TaskDashboardServiceTest,TaskMutationBoundaryTest,TaskCreationIntegrationTest test
|
||||
|
||||
[INFO] Tests run: 51, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
These unit tests establish service call order and repository lock metadata; they do not simulate two concurrent database transactions. PostgreSQL execution of the locked Task lookup is covered by `TaskCreationIntegrationTest`, and the producing Project feature separately proves its locked DTO boundary. Broader concurrency stress remains the explicit Iteration 3 hardening scope.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Test Evidence: Task feature persistence structure
|
||||
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `TSK-001`–`TSK-005`, `TSK-007`, `TSK-011`, `TSK-012`
|
||||
- **Scenario IDs:** `I1-TSK-01`–`I1-TSK-04`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.repository.TaskPersistenceStructureTest#taskPersistenceUsesJpaEntitiesAndSpringDataRepositories`
|
||||
- **Implementation commit:** `pending`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Task persistence uses JPA entities in `feature.task.model.entity` and Spring Data repositories in `feature.task.repository`. Status/comment mutation lookup is protected by `PESSIMISTIC_WRITE`. This prevents a regression to business-level JDBC access, unlocked mutation reads, or a global layer package.
|
||||
|
||||
## Test method
|
||||
|
||||
Four focused tests load the production `Task` and `TaskComment` classes, verify their `@Entity` annotations, verify that both production repository interfaces extend `JpaRepository`, reject direct JDBC imports in Task business code, and inspect the locked lookup's `@Lock(PESSIMISTIC_WRITE)` annotation.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
Exactly two Task-owned persisted aggregates are required for Iteration 1: `Task` and append-only `TaskComment`. Each must be a JPA entity, and each repository must be a Spring Data JPA repository under the Task feature package.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskPersistenceStructureTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] TaskPersistenceStructureTest.java:[5,54] package com.lab.labtimesheet.feature.task.model.entity does not exist
|
||||
[ERROR] TaskPersistenceStructureTest.java:[6,54] package com.lab.labtimesheet.feature.task.model.entity does not exist
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The final feature-first package contract did not yet exist.
|
||||
|
||||
After that package move reached GREEN, the business-persistence boundary was tightened with a second test and separately observed RED:
|
||||
|
||||
```text
|
||||
[ERROR] Tests run: 3, Failures: 2, Errors: 0, Skipped: 0
|
||||
Expecting [org.springframework.jdbc.core.simple.JdbcClient]
|
||||
to contain [TaskRepository, TaskCommentRepository]
|
||||
Expecting empty but was: [src/main/java/com/lab/labtimesheet/feature/task/service/TaskService.java]
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The second failure proves that `TaskService` still depended on direct JDBC instead of the two Task-owned Spring Data repositories.
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskPersistenceStructureTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## Affected suite
|
||||
|
||||
**Command and result**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
||||
./mvnw -Dtest=TaskPersistenceStructureTest,TaskDomainRulesTest,TaskControllerTest,TaskQueryServiceTest,TaskDashboardServiceTest,TaskMutationBoundaryTest,TaskCreationIntegrationTest test
|
||||
|
||||
[INFO] Tests run: 51, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
The suite ran with approved escalation for PostgreSQL 18.4 Testcontainers and Mockito Java 25 self-attach.
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This structure test does not prove persistence mappings against PostgreSQL, transactional authorization, cross-feature service contracts, or rendered behavior. Those remain protected by the Task integration and web evidence after the dependency foundations are merged.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Test Evidence: Project activation Task-assignment query
|
||||
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `PRJ-012`
|
||||
- **Scenario IDs:** `I1-PRJ-04`, `AC-PRJ-006`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.service.TaskQueryServiceTest`
|
||||
- **Implementation commit:** `pending`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
The Project feature can ask the public Task service whether any current non-deleted Task is assigned outside the Project's active membership set, without accessing Task repositories or entities.
|
||||
|
||||
## Test method
|
||||
|
||||
Two focused Mockito tests exercise the concrete public service. An empty active-membership set counts every current Task without issuing an invalid `NOT IN ()` query. A non-empty set delegates to the filtered Spring Data repository query.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
With no active memberships, all three current Tasks are invalid assignments. With active memberships 7 and 9, the repository-derived count of assignments outside that set is two.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskQueryServiceTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] TaskQueryServiceTest.java:[22,13] cannot find symbol
|
||||
symbol: class TaskQueryService
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskQueryServiceTest test
|
||||
```
|
||||
|
||||
Run with approved sandbox escalation for Mockito Java 25 self-attach.
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## Affected suite
|
||||
|
||||
**Command and result**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
||||
./mvnw -Dtest=TaskPersistenceStructureTest,TaskDomainRulesTest,TaskControllerTest,TaskQueryServiceTest,TaskDashboardServiceTest,TaskMutationBoundaryTest,TaskCreationIntegrationTest test
|
||||
|
||||
[INFO] Tests run: 51, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This unit test does not prove the JPQL query against PostgreSQL or Project activation integration. The Task PostgreSQL suite and the Project feature's own integration tests cover those boundaries after dependency merge.
|
||||
@@ -3,7 +3,7 @@
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `TSK-007`, `TSK-008`, `PRJ-015`, `PRJ-016`
|
||||
- **Scenario IDs:** `I1-TSK-03`, `I1-TSK-05`, `AC-TSK-003`, `AC-PRJ-008`
|
||||
- **Test class/method:** `com.lab.labtimesheet.tasks.TaskDomainRulesTest`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.model.TaskDomainRulesTest`
|
||||
- **Implementation commit:** `17a3c5d`
|
||||
|
||||
## Protected behavior
|
||||
@@ -66,7 +66,7 @@ export PATH="$JAVA_HOME/bin:$PATH"
|
||||
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
||||
./mvnw test
|
||||
|
||||
[INFO] Tests run: 19, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] Tests run: 107, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user