Merge commit '213a889c8f0a475abfdb06082065320379d9bc7a' into work/reports-ui
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# Test Evidence: Completed Project member and Task history
|
||||
|
||||
- **Test type:** Integration
|
||||
- **Requirement IDs:** `AUTH-006`, `PRJ-014`
|
||||
- **Scenario IDs:** `AC-AUTH-007`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.service.ProjectServiceIntegrationTest#completedProjectQueriesReturnHistoricalMembersWithoutRequiringACurrentLeader`
|
||||
- **Implementation commit:** `3d954dd`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
After Project completion closes every membership and leadership interval, a historical member can still retrieve read-only Task context and member history. The Task context reports no current Leader and no active members, and every historical member row reports `currentLeader=false`.
|
||||
|
||||
## Test method
|
||||
|
||||
The Spring Boot integration test creates a Project and second member through public Project services, then uses direct SQL only as a fixture to reproduce the Iteration 2 completion result: all leadership and membership intervals are closed and the Project is marked `COMPLETED`. After clearing the persistence context, it calls the public Project query APIs as the former member and checks the DTOs.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
A completed Project cannot have a current Leader or active member. Therefore `ProjectTaskContext.currentLeaderMembershipId` is `null`, `activeMembers` is empty, both membership-history rows remain visible, both have leave timestamps, and neither is marked as current Leader.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```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=ProjectServiceIntegrationTest#completedProjectQueriesReturnHistoricalMembersWithoutRequiringACurrentLeader test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] ProjectRuleViolationException: Project has no current Leader
|
||||
at com.lab.labtimesheet.feature.project.model.entity.ProjectEntity.currentLeader(ProjectEntity.java:232)
|
||||
at com.lab.labtimesheet.feature.project.service.ProjectQueryService.taskContext(ProjectQueryService.java:113)
|
||||
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```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=ProjectServiceIntegrationTest#completedProjectQueriesReturnHistoricalMembersWithoutRequiringACurrentLeader test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Running com.lab.labtimesheet.feature.project.service.ProjectServiceIntegrationTest
|
||||
[INFO] Tests run: 1, 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='Project*Test' test
|
||||
|
||||
[INFO] Tests run: 21, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This regression proves completed-state DTO behavior against PostgreSQL 18.4. It does not implement or test the future Project-completion mutation itself, browser rendering, or Task-owned authorization and presentation; direct SQL is confined to constructing the completed aggregate fixture.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Test Evidence: Atomic Project workflows
|
||||
|
||||
- **Test type:** Integration
|
||||
- **Requirement IDs:** `PRJ-001`–`PRJ-007`, `PRJ-017`, `AUTH-001`–`AUTH-004`, `DB-003`, `DB-007`
|
||||
- **Scenario IDs:** `AC-PRJ-001`–`AC-PRJ-003`, `AC-PRJ-009`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.service.ProjectServiceIntegrationTest`
|
||||
- **Implementation commit:** `25a855e`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
PostgreSQL transactions persist a planned Project with its initial membership and leadership term, reject unauthorized or duplicate direct additions, change exactly one Leader without moving Task assignments, and enforce role/membership visibility without ID disclosure.
|
||||
|
||||
## Test method
|
||||
|
||||
A Spring Boot integration test uses the platform-owned PostgreSQL 18.4 Testcontainer and Flyway V1 schema. It calls the public Project service and verifies committed-shape rows and negative-case non-mutation with independent SQL.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
Creation yields one Project, one active membership, and one current leadership term. Direct addition yields one membership per Project/Intern pair while allowing the same Intern in a second Project. Leader change yields one closed and one current term while the Task assignee ID remains unchanged. Admin, owner, and historical member visibility is allowed; unrelated IDs are denied uniformly.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```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=ProjectServiceIntegrationTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] cannot find symbol: class CreateProjectCommand
|
||||
[ERROR] cannot find symbol: class ProjectService
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```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=ProjectServiceIntegrationTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Running com.lab.labtimesheet.feature.project.service.ProjectServiceIntegrationTest
|
||||
[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 test
|
||||
|
||||
[INFO] Tests run: 25, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This test does not prove MockMvc authorization, Thymeleaf rendering, browser accessibility, real concurrent transaction races, Iteration 2 invitations/removals/completion, or Task-module business rules beyond preserving stored assignment IDs. `I1-PRJ-04` remains `IN_PROGRESS`: the activation Task-assignee guard will be implemented only after the Task feature exposes its concrete query service.
|
||||
@@ -0,0 +1,101 @@
|
||||
# Test Evidence: Iteration 1 Task persistence and authorization
|
||||
|
||||
- **Test type:** Integration
|
||||
- **Requirement IDs:** `AUTH-001`, `AUTH-002`, `AUTH-005`–`AUTH-009`, `AUTH-011`, `PRJ-013`, `PRJ-015`, `PRJ-016`, `TSK-001`–`TSK-005`, `TSK-007`, `TSK-008`, `TSK-011`, `TSK-012`, `TSK-018`
|
||||
- **Scenario IDs:** `I1-TSK-01`–`I1-TSK-05`, `AC-AUTH-001`, `AC-AUTH-003`–`AC-AUTH-007`, `AC-AUTH-010`, `AC-PRJ-008`, `AC-TSK-002`, `AC-TSK-003`, `AC-TSK-006`, `AC-TSK-010`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.service.TaskCreationIntegrationTest`
|
||||
- **Implementation commit:** `511ee81a91a79a61cc6afb00097e1b38577c1968`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
PostgreSQL-backed Task operations preserve generic same-Project membership actors, limit ordinary members to self-Task creation, allow current Leaders to assign active same-Project members, validate due dates, restrict status changes to the active current assignee, append authorized comments, exclude deleted Tasks from current reads/progress, render assignee names and empty progress, deny guessed/cross-Project identifiers without writes, give former members read-only access only after completion, and execute the Project-activation and dashboard Task queries.
|
||||
|
||||
## Test method
|
||||
|
||||
Thirteen transactional Spring integration tests create real users, Intern profiles, Projects, memberships, leadership terms, calendar events, Tasks, and comments against the approved PostgreSQL 18.4 V1 schema. Assertions inspect returned behavior and persisted rows; there are no mocked domain or database operations.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
A self-Task stores one membership in creator, assigner, and assignee fields. A Leader-created Task retains the Leader membership as creator/assigner and the selected member as assignee. Project start/end due dates are valid; dates before, after, or on a current global day off are invalid. Only an active Project's current assignee can traverse an allowed status edge. Authorized member/Mentor comments append two rows. Four current Tasks with one in each status produce 25% and four unit counts; a deleted fifth Task is absent; zero Tasks has no percentage.
|
||||
|
||||
A former member cannot read Task data while the Project remains planned or active, but can read the completed Project history. List/detail views resolve the assignee display name from the Project service boundary, and their capability flags match current membership, assignment, role, and Project lifecycle.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```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=TaskCreationIntegrationTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] TaskCreationIntegrationTest.java:[6,34] cannot find symbol
|
||||
symbol: class CreateTaskCommand
|
||||
[ERROR] TaskCreationIntegrationTest.java:[8,34] cannot find symbol
|
||||
symbol: class TaskService
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
After creation reached GREEN, the next cohesive workflow increment was separately observed RED:
|
||||
|
||||
```text
|
||||
[ERROR] TaskCreationIntegrationTest.java:[7,34] cannot find symbol
|
||||
symbol: class TaskCommentView
|
||||
[ERROR] TaskCreationIntegrationTest.java:[8,34] cannot find symbol
|
||||
symbol: class TaskDetails
|
||||
[ERROR] TaskCreationIntegrationTest.java:[9,34] cannot find symbol
|
||||
symbol: class TaskListView
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The review-hardening increment was also observed RED before its implementation. The former-member PostgreSQL regression reached the old list behavior instead of throwing, and the view-contract tests could not compile because `assigneeName`, `canCreate`, `canChangeStatus`, and `canComment` did not exist.
|
||||
|
||||
The second review then made the completed-history fixture production-shaped by closing the current leadership term and all memberships. That focused test was observed RED because the Project read boundary still required `currentLeader()` for a completed Project:
|
||||
|
||||
```text
|
||||
[ERROR] TaskCreationIntegrationTest.formerMemberReadsOnlyCompletedProjectTaskHistory
|
||||
» TaskNotFound Task or Project was not found
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```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=TaskCreationIntegrationTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 13, 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 test
|
||||
|
||||
[INFO] Tests run: 107, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This evidence does not prove browser behavior, shared-shell integration, notification delivery, Iteration 2 work logs/reassignment/edit/deletion, or Iteration 3 concurrency/index plans. The status edge matrix is separately protected by unit evidence. HTTP form, CSRF, template, and direct-route behavior require the companion web evidence.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Test Evidence: Locked Project context for Task mutations
|
||||
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `AUTH-001`, `AUTH-011`, `PRJ-012`
|
||||
- **Scenario IDs:** `AC-AUTH-001`, `AC-AUTH-010`, `AC-PRJ-006`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.service.ProjectTaskMutationContextTest#loadsTheProjectForUpdateBeforeBuildingTheTaskMutationContext`
|
||||
- **Implementation commit:** `19a3518`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Task mutations obtain their Project authorization and current lifecycle, Leader, owning-Mentor, and active-member facts from a DTO-only Project service boundary after the Project row has been locked for update. Missing and unauthorized Projects retain the same non-disclosing denial behavior.
|
||||
|
||||
## Test method
|
||||
|
||||
The isolated service test invokes `ProjectService.taskMutationContext(actorUserId, projectId)`, verifies that `ProjectRepository.findLockedById` is used and the ordinary `findById` path is not used, and verifies that only the locked entity is passed to the existing Project-owned authorization and DTO mapper. The PostgreSQL integration test additionally exercises the public API with authorized, unauthorized, current-member, and former-member data.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
Exactly one pessimistic Project lookup occurs before context evaluation. The returned `ProjectTaskContext` exposes scalar/DTO facts only; no Project repository or entity crosses the feature boundary. When called from Task's active transaction, Spring's default `REQUIRED` propagation keeps the row lock in that transaction through its commit or rollback.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectTaskMutationContextTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] constructor ProjectService ... cannot be applied to given types
|
||||
[ERROR] incompatible types: ProjectEntity cannot be converted to long
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The test failed to compile because Project had no mutation-context API and its context mapper accepted only an unlocked Project ID lookup.
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectTaskMutationContextTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Running com.lab.labtimesheet.feature.project.service.ProjectTaskMutationContextTest
|
||||
[INFO] Tests run: 1, 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='Project*Test' test
|
||||
|
||||
[INFO] Tests run: 20, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
The unit test proves the locked repository path and DTO-only handoff, while the integration coverage proves current Project authorization/member mapping against PostgreSQL 18.4. It does not orchestrate two concurrent database transactions; the lock-retention guarantee relies on the public method's `@Transactional` default `REQUIRED` propagation and the Task caller retaining its outer transaction.
|
||||
@@ -3,8 +3,8 @@
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `PRJ-001`–`PRJ-007`, `PRJ-012`, `PRJ-017`, `AUTH-001`–`AUTH-004`
|
||||
- **Scenario IDs:** `AC-PRJ-001`, `AC-PRJ-003`, `AC-PRJ-006`, `AC-PRJ-009`
|
||||
- **Test class/method:** `com.lab.labtimesheet.projects.domain.ProjectTest`
|
||||
- **Implementation commit:** `3483347`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.model.entity.ProjectEntityTest`
|
||||
- **Implementation commit:** `25a855e`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
@@ -43,13 +43,13 @@ export PATH="$JAVA_HOME/bin:$PATH"
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectTest test
|
||||
./mvnw -Dtest=ProjectEntityTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Running com.lab.labtimesheet.projects.domain.ProjectTest
|
||||
[INFO] Running com.lab.labtimesheet.feature.project.model.entity.ProjectEntityTest
|
||||
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
@@ -61,7 +61,7 @@ export PATH="$JAVA_HOME/bin:$PATH"
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectTest test
|
||||
./mvnw -Dtest=ProjectEntityTest test
|
||||
|
||||
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Test Evidence: Project layer and JPA structure
|
||||
|
||||
- **Test type:** Unit
|
||||
- **Requirement IDs:** `ARC-002`, `ARC-005`–`ARC-007`, `OPS-018`–`OPS-020`, `TST-001`–`TST-010`
|
||||
- **Scenario IDs:** `I1-PRJ-01`–`I1-PRJ-05`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.repository.ProjectPersistenceStructureTest#projectPersistenceUsesTheRequiredLayerPackagesAndSpringDataJpa`
|
||||
- **Implementation commit:** `25a855e`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Project-owned production code follows the authoritative feature-first package layout, persists aggregate entities through Spring Data JPA, keeps JDBC operations out of Project business services, and does not shadow Account or Task persistence.
|
||||
|
||||
## Test method
|
||||
|
||||
Plain JUnit inspects the public Project entity, repository, and service types. It verifies their exact feature/layer packages, the entity's JPA mapping, the repository's `JpaRepository` contract, the absence of JDBC service dependencies, and the absence of foreign-table Account/Task shadow entities.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
The Project aggregate is under `feature.project.model.entity`, persistence under `feature.project.repository`, business logic under `feature.project.service`, the service has zero JDBC collaborators, and Account/Task persistence remains owned by those features.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectPersistenceStructureTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] cannot find symbol: class ProjectUserRepository
|
||||
[ERROR] cannot find symbol: class ProjectInternProfileRepository
|
||||
[ERROR] cannot find symbol: class ProjectTaskRepository
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The RED was observed after removing Project-owned shadow mappings of Account and Task tables. It proves the service still required cross-feature dependencies and could not be made green by retaining forbidden repositories.
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectPersistenceStructureTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Running com.lab.labtimesheet.feature.project.repository.ProjectPersistenceStructureTest
|
||||
[INFO] Tests run: 1, 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"
|
||||
./mvnw -Dtest=LayerStructureTest,ProjectPersistenceStructureTest,ProjectEntityTest test
|
||||
|
||||
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This check does not prove database mappings, transaction behavior, MVC routing, or runtime authorization; those remain covered by PostgreSQL and MockMvc tests.
|
||||
@@ -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:** `511ee81a91a79a61cc6afb00097e1b38577c1968`
|
||||
|
||||
## 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:** `511ee81a91a79a61cc6afb00097e1b38577c1968`
|
||||
|
||||
## 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:** `511ee81a91a79a61cc6afb00097e1b38577c1968`
|
||||
|
||||
## 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:** `511ee81a91a79a61cc6afb00097e1b38577c1968`
|
||||
|
||||
## 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.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Test Evidence: Fixed Task status graph and initial Project progress
|
||||
|
||||
- **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.feature.task.model.TaskDomainRulesTest`
|
||||
- **Implementation commit:** `17a3c5d`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
The Task status graph accepts exactly the seven specified directed edges. Initial Project progress counts each current Task status and represents a Project without current Tasks as no percentage rather than zero percent.
|
||||
|
||||
## Test method
|
||||
|
||||
One parameterized test checks all 16 source/target status pairs against a hand-written allowed-edge table. Two focused tests check empty progress and a four-Task example with two `DONE` Tasks.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
Allowed edges are `TODO` to `IN_PROGRESS` or `BLOCKED`; `IN_PROGRESS` to `DONE` or `BLOCKED`; `BLOCKED` to `TODO` or `IN_PROGRESS`; and `DONE` to `IN_PROGRESS`. All other pairs are forbidden. Zero Tasks has no percentage. Two `DONE` among four Tasks is 50%, with counts 1 `TODO`, 1 `IN_PROGRESS`, 0 `BLOCKED`, and 2 `DONE`.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskDomainRulesTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] COMPILATION ERROR :
|
||||
TaskDomainRulesTest.java:[16,30] cannot find symbol
|
||||
symbol: class TaskStatus
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The test could not compile because the required Task status and progress domain types did not exist.
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskDomainRulesTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 18, 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 test
|
||||
|
||||
[INFO] Tests run: 107, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This unit evidence does not prove current-assignee authorization, Project lifecycle enforcement, PostgreSQL persistence/query filtering, non-deleted selection, HTTP authorization, or rendered `N/A`. Those require the platform/Project foundation and PostgreSQL/web tests.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Test Evidence: Authorized Project pages
|
||||
|
||||
- **Test type:** Web
|
||||
- **Requirement IDs:** `AUTH-001`, `AUTH-002`, `AUTH-006`, `PRJ-001`, `PRJ-004`–`PRJ-006`, `SEC-001`, `ERR-001`
|
||||
- **Scenario IDs:** `AC-AUTH-001`, `AC-AUTH-002`, `AC-AUTH-007`, `I1-PRJ-05`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.project.controller.ProjectControllerTest`
|
||||
- **Implementation commits:** `25a855e`, `a9ee99a`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Authenticated users receive only authorized Project routes; guessed IDs return a non-disclosing not-found response; valid Mentor create requests use the authenticated identity; invalid forms do not mutate; state changes require CSRF.
|
||||
|
||||
## Test method
|
||||
|
||||
MockMvc exercises the real controller, binding, Bean Validation, exception mapping, view selection, redirect, Spring Security authentication, and CSRF filter. Only application/query services are mocked.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
An authorized list request renders `projects/list`. An unauthorized direct ID returns 404. Member and leadership routes authorize through actor plus Project ID. A valid create redirects to the created detail ID; a blank name and zero Leader ID render field errors and make no service call. POST without CSRF returns 403.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectControllerTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] cannot find symbol: class ProjectController
|
||||
[ERROR] cannot find symbol: class ProjectPageService
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=ProjectControllerTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Running com.lab.labtimesheet.feature.project.controller.ProjectControllerTest
|
||||
[INFO] Tests run: 6, 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 test
|
||||
|
||||
[INFO] Tests run: 25, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
## Mentor-only control regression
|
||||
|
||||
**RED:** the focused MockMvc run reported two expected failures: `GET /projects/new` returned `200` for an Intern instead of non-disclosing `404`, and the member page rendered the `Add member` form for a non-owner.
|
||||
|
||||
**GREEN:** rerunning `./mvnw -Dtest=ProjectControllerTest test` after the controller/DTO/template correction passed 7 tests with zero failures, errors, or skips.
|
||||
|
||||
## Role-aware Project-list action regression
|
||||
|
||||
**RED:** the focused MockMvc run reported two expected failures after adding the list-action regression: the controller still resolved only a user ID, so the Mentor fixture was queried as user `0`, and an Intern-facing Project list rendered the `Create Project` link.
|
||||
|
||||
**GREEN:** rerunning `./mvnw -Dtest=ProjectControllerTest test` after resolving the public actor view and conditionally rendering the link passed 8 tests with zero failures, errors, or skips.
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This slice does not prove PostgreSQL query correctness, a real login flow, shared-shell navigation, browser accessibility, or Iteration 2 invitation/exit/completion pages. The activation route remains deferred with `I1-PRJ-04` until the Task feature query dependency is available.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Test Evidence: Task pages and server-side request boundaries
|
||||
|
||||
- **Test type:** Web
|
||||
- **Requirement IDs:** `AUTH-001`, `AUTH-002`, `AUTH-005`, `AUTH-009`, `AUTH-011`, `PRJ-015`, `TSK-003`, `TSK-007`, `TSK-011`, `TSK-012`
|
||||
- **Scenario IDs:** `I1-TSK-01`, `I1-TSK-03`–`I1-TSK-05`, `AC-AUTH-001`, `AC-AUTH-006`, `AC-AUTH-010`, `AC-PRJ-008`, `AC-TSK-003`, `AC-TSK-006`, `AC-TSK-010`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.task.controller.TaskControllerTest`
|
||||
- **Implementation commit:** `511ee81a91a79a61cc6afb00097e1b38577c1968`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Task list/detail/create/status/comment routes require authentication, obtain actor identity from Spring Security rather than request IDs, retain CSRF protection, convert guessed-record denial to HTTP 404, validate create input, render the actual Thymeleaf pages, show `N/A` for an empty Project, display assignees, and expose create/status/comment controls only when the service-provided capability permits them.
|
||||
|
||||
## Test method
|
||||
|
||||
Nine `@WebMvcTest` MockMvc tests render the real Task templates and exercise the real controller, Spring Security filter chain, CSRF filter, Bean Validation binding, redirect contracts, exception-to-status mapping, assignee output, and capability-controlled actions. Only the PostgreSQL-backed Task service is replaced at the controller boundary.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
Unauthenticated list access returns 401 under the current platform security baseline. An authorized empty list returns 200 and contains `N/A`. A denied guessed Task returns 404. A valid create request passes Project 10, assignee membership 7, the supplied fields, and the authenticated email to the service, then redirects to Task 25. Blank title stays on the form with a field error and no write. Valid status/comment posts redirect to Task 25.
|
||||
|
||||
When `canCreate`, `canChangeStatus`, or `canComment` is false, the corresponding control is absent. When true, it is rendered. Both list and detail output the assignee display name.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskControllerTest test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[ERROR] TaskControllerTest.java:[28,13] cannot find symbol
|
||||
symbol: class TaskController
|
||||
[INFO] BUILD FAILURE
|
||||
```
|
||||
|
||||
The first sandboxed GREEN attempt then exposed an environment boundary, not an application failure: Mockito could not use Java 25 self-attach inside the restricted sandbox. The exact same command was rerun with approved escalation; one test expectation was corrected from a login redirect to the platform baseline's observed 401 response before the final GREEN run.
|
||||
|
||||
The later view-capability increment was observed RED at test compilation because the Task DTOs did not yet provide the required capability and assignee fields.
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
./mvnw -Dtest=TaskControllerTest test
|
||||
```
|
||||
|
||||
Run with approved sandbox escalation for Mockito Java 25 self-attach.
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
[INFO] Tests run: 9, 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 test
|
||||
|
||||
[INFO] Tests run: 107, Failures: 0, Errors: 0, Skipped: 0
|
||||
[INFO] BUILD SUCCESS
|
||||
```
|
||||
|
||||
The suite ran with approved escalation for OrbStack and Mockito self-attach.
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
This slice test does not prove PostgreSQL state changes; those are covered by `TaskCreationIntegrationTest`. Shared shell styling/navigation remains owned by `work/reports-ui`. Browser journeys, notifications, Iteration 2 workflows, and narrow-screen behavior are outside this Iteration 1 Task evidence.
|
||||
Reference in New Issue
Block a user