Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
- name: Install dependencies
if: steps.detect.outputs.found == 'true'
run: make ci-setup
# Actions 會設 CI=true:make test 一律跑含容器的全部測試(見 docs/design/INIT-01.md「驗證方式」)
- name: Check
if: steps.detect.outputs.found == 'true'
run: make check
15 changes: 13 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ COMPOSE := docker compose --env-file "$(ROOT)/.env" -f docker-compose.yml
help:
@echo "make setup install deps (Maven repo in ~/.m2, node_modules at checkout root)"
@echo "make ci-setup install deps in CI (same steps as setup)"
@echo "make check lint + tests (incl. acceptance tests)"
@echo "make check lint + tests (container tests skipped when Docker is unreachable)"
@echo "backend tests incl. containers, from main checkout as one command:"
@echo " docker compose --env-file .env -f .worktrees/<task_id>/compose.yaml run --rm test"
@echo "make infra-up start local PostgreSQL + RabbitMQ (docker compose)"
@echo "make infra-down stop local services (data kept)"
@echo "make api-run run backend on API_PORT"
Expand Down Expand Up @@ -58,9 +60,18 @@ lint:
else echo "skip web lint: no $(WEB_DIR)/package.json"; fi

# mvnw verify 跑 src/test/java 全部(含 com.cdp.acceptance);vitest 跑 src/ 與 tests/(含 tests/acceptance)
# 連不到 Docker(本機 sandbox)或 CONTAINER_TESTS=skip 時用 -Punit-only 略過需要容器的測試並提示 compose 指令;
# CI(CI 變數非空)一律跑全部,Docker 有問題就直接失敗。見 docs/design/INIT-01.md「驗證方式」
test:
@if [ -f "$(API_DIR)/pom.xml" ]; then \
cd "$(API_DIR)" && $(NO_DOTENV) $(MVNW) verify; \
if [ -n "$$CI" ] || { [ "$(CONTAINER_TESTS)" != skip ] && timeout 15 docker info >/dev/null 2>&1; }; then \
cd "$(API_DIR)" && $(NO_DOTENV) $(MVNW) verify; \
else \
echo "Docker not reachable or CONTAINER_TESTS=skip: skipping container tests (acceptance/, *IntegrationTest)."; \
echo "Run all backend tests from the main checkout as a single command:"; \
echo " docker compose --env-file .env -f .worktrees/<task_id>/compose.yaml run --rm test"; \
cd "$(API_DIR)" && $(NO_DOTENV) $(MVNW) -Punit-only verify; \
fi; \
else echo "skip api tests: no $(API_DIR)/pom.xml"; fi
@if [ -f "$(WEB_DIR)/package.json" ]; then \
$(NO_DOTENV) npm test -w "$(WEB_DIR)"; \
Expand Down
23 changes: 23 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,27 @@
</plugin>
</plugins>
</build>

<profiles>
<!-- 沒有 Docker 時(本機 sandbox)make test 用:略過需要容器的測試,完整測試走 compose.yaml 的 test 服務
(見 docs/design/INIT-01.md「驗證方式」)。需要容器的測試只能放 acceptance/ 或命名為 *IntegrationTest。 -->
<profile>
<id>unit-only</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/*$*</exclude>
<exclude>com/cdp/acceptance/**</exclude>
<exclude>**/*IntegrationTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
37 changes: 37 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 本機跑後端全部測試(含 acceptance/)的入口;用法與取捨見 docs/design/INIT-01.md「驗證方式」。
# 在主目錄單獨一行執行(不可包進 make/script):
# docker compose --env-file .env -f .worktrees/<id>/compose.yaml run --rm test
# 不設 name:專案名稱 = compose 檔所在目錄(worktree 名稱),平行的單各自一套。
# 本地 PostgreSQL/RabbitMQ 仍在 docker-compose.yml(make infra-up),與此檔無關。

services:
test:
image: eclipse-temurin:17-jdk
# 掛 Docker socket:測試沿用 Testcontainers 自起 PostgreSQL/RabbitMQ(含 docker pause)。
# socket 等同主機 Docker 的 root 權限,故以 root 跑、原始碼唯讀掛載、不寫回主機。
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./api:/src/api:ro
# EnvExampleNoTenantIdAcceptanceTest 從 user.dir 往上找 .env.example
- ./.env.example:/workspace/.env.example:ro
# Maven 相依與 wrapper 下載的快取;固定名稱,所有 worktree 共用
- m2:/root/.m2
environment:
# Testcontainers 起的容器是主機 Docker 的兄弟容器,經主機的對外 port 連
TESTCONTAINERS_HOST_OVERRIDE: host.docker.internal
extra_hosts:
# Linux 引擎沒有內建 host.docker.internal;Docker Desktop 照常
- "host.docker.internal:host-gateway"
working_dir: /workspace/api
# 複製原始碼(不含 target/)到容器內再建置:主機的 api/target 不受影響、不留 root 擁有的檔案
command:
- sh
- -c
- >-
mkdir -p /workspace/api &&
tar -C /src/api --exclude=./target -cf - . | tar -C /workspace/api -xf - &&
sh ./mvnw -B -ntp verify -Dsurefire.useFile=false

volumes:
m2:
name: cdp-test-m2
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 本機外部服務。由 make infra-up / infra-down 操作(會帶 --env-file 主目錄 .env);變數說明見 .env.example。
# 只放 v0.1.0 需要的服務(PostgreSQL、RabbitMQ);Redis 等見 docs/design/INIT-01.md「延後」,不要先加。
# 測試不用這套:後端整合測試由 Testcontainers 自起容器(映像版本須與此一致)。
# 測試不用這套:後端整合測試由 Testcontainers 自起容器(映像版本須與此一致);本機跑法見 compose.yaml。
name: cdp

services:
Expand Down
14 changes: 14 additions & 0 deletions docs/design/INIT-01.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@
| 6 | 相依只在用到的那張設計單加進 `api/pom.xml`(PostgreSQL、Flyway、AMQP 皆留給 v0.1.0 設計單,見 D-009) | 骨架不連外部服務,`make check` 不需 Docker |
| 7 | spec 與本設計的已知差異,由 v0.1.0 設計單修訂 `docs/spec/`:README 第 4 行 `../plan/` 改指計劃書路徑;README「`next_wake_at` 供 db-scheduler」改依 R1;spec 05 管線入口改為「outbox → relay → RabbitMQ」 | spec 是前後端契約的上游,不可與設計矛盾 |

## 驗證方式(compose-test-setup)
| 情境 | 指令 | 跑什麼 |
|---|---|---|
| 本機全部後端測試(含 `acceptance/`) | 在主目錄單獨一行:`docker compose --env-file .env -f .worktrees/<id>/compose.yaml run --rm test`(主目錄本身用 `-f compose.yaml`) | `compose.yaml` 的 `test` 服務:`eclipse-temurin:17-jdk`,把唯讀掛載的 `api/`(不含 `target/`)複製進容器後 `mvnw verify`;不讀 `.env` 的值 |
| `make check` | 照舊 | Docker 連得到(或 CI 變數非空)跑全部;連不到或 `CONTAINER_TESTS=skip` 改 `-Punit-only`(`api/pom.xml`,排除 `com/cdp/acceptance/**`、`*IntegrationTest`),並印出上一列指令 |
| CI | `make check`(不變) | GitHub Actions 設 `CI=true`,一律全跑,Docker 壞了就紅燈 |

| 項目 | 做法與取捨 |
|---|---|
| Testcontainers | 沿用(不改測試、`docker pause` 照常):`test` 掛 `/var/run/docker.sock`,PG/RabbitMQ 是主機引擎上的兄弟容器,經 `TESTCONTAINERS_HOST_OVERRIDE=host.docker.internal`(Linux 由 `extra_hosts: host-gateway` 補)連對外 port;Ryuk 照常清理 |
| 安全 | socket 等同主機 Docker root 權限,故只掛 `api/`、`.env.example`(皆唯讀)與 Maven 快取 volume,不寫回主機(所以以 root 跑、不需 `HOST_UID`);Testcontainers 對外 port 與在主機直接跑時相同 |
| 隔離與殘留 | 不設 `name:`,專案名 = worktree 目錄;`run --rm` 刪 `test` 容器,Testcontainers 容器由 Ryuk 收;留下的只有專案網路(`docker compose -f … down` 可刪)與共用快取 volume `cdp-test-m2` |
| 新測試慣例 | 需要容器的測試只放 `acceptance/` 或命名 `*IntegrationTest`,否則 sandbox 的 `make check` 會失敗 |

## RabbitMQ(D-006;守計劃書 7.2.1 三條紅線)
| 項目 | 設計 |
|---|---|
Expand Down
Loading