From f3b13bf7b2523e1f0d690b505c0a673a11be498f Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Sat, 3 Oct 2026 17:59:09 +0900 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20=EC=BA=90=EC=8B=9C=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=EB=A5=BC=20Redis=207.4=EC=97=90=EC=84=9C=20Valkey?= =?UTF-8?q?=EB=A1=9C=20=EA=B5=90=EC=B2=B4=20(#399)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker-compose의 redis:7-alpine은 실제로 Redis 7.4.10을 실행하며, 이 버전의 라이선스(RSALv2/SSPLv1)는 OSI 승인을 받지 못해 대회 라이선스 기준에 걸릴 수 있다. Redis 프로토콜과 호환되는 BSD-3-Clause 라이선스의 Valkey로 서버만 교체한다. - docker-compose.yml: 서비스·컨테이너·볼륨을 valkey로 변경하고 이미지를 valkey/valkey:9.1-alpine(마이너 버전까지 고정), healthcheck를 valkey-cli ping으로 변경 - monitoring/drills: 장애 훈련용 compose와 run_drill.py의 서비스명 참조를 동일하게 변경 - scripts/local-services.sh: valkey-cli 상태 확인과 valkey 서비스 기동으로 변경 자바 코드, application.yml, REDIS_* 환경변수는 Spring Data Redis(Apache-2.0)와 Lettuce(MIT)가 그대로 Valkey에 접속하므로 변경하지 않는다. Co-Authored-By: Claude Sonnet 5.5 --- docker-compose.yml | 12 ++++++------ monitoring/drills/docker-compose.yml | 6 +++--- monitoring/drills/run_drill.py | 4 ++-- scripts/local-services.sh | 24 ++++++++++++------------ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c5d2ee47..4bafefe5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -118,16 +118,16 @@ services: networks: - docgrid-local - redis: - image: redis:7-alpine - container_name: docgrid-redis + valkey: + image: valkey/valkey:9.1-alpine + container_name: docgrid-valkey restart: unless-stopped ports: - "127.0.0.1:${REDIS_PORT:-6379}:6379" volumes: - - redis-data:/data + - valkey-data:/data healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: ["CMD", "valkey-cli", "ping"] interval: 10s timeout: 5s retries: 5 @@ -142,6 +142,6 @@ volumes: name: docgrid_postgres17_data minio-data: huggingface-cache: - redis-data: + valkey-data: prometheus-data: alertmanager-data: diff --git a/monitoring/drills/docker-compose.yml b/monitoring/drills/docker-compose.yml index 20ce095e..84dbfc0d 100644 --- a/monitoring/drills/docker-compose.yml +++ b/monitoring/drills/docker-compose.yml @@ -23,12 +23,12 @@ services: timeout: 2s retries: 30 - redis: - image: redis:7-alpine + valkey: + image: valkey/valkey:9.1-alpine ports: - "127.0.0.1::6379" healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: ["CMD", "valkey-cli", "ping"] interval: 1s timeout: 1s retries: 30 diff --git a/monitoring/drills/run_drill.py b/monitoring/drills/run_drill.py index f8f3100a..a64c73cc 100755 --- a/monitoring/drills/run_drill.py +++ b/monitoring/drills/run_drill.py @@ -159,14 +159,14 @@ def compose(self, *arguments, capture=True, check=True): def start_core(self, *, include_provider): """Start fresh database, cache, local receiver, Alertmanager, and optionally BGE-M3.""" - services = ["postgres", "redis", "webhook-receiver", "alertmanager"] + services = ["postgres", "valkey", "webhook-receiver", "alertmanager"] if include_provider: run(["docker", "volume", "create", "docgrid_huggingface-cache"]) services.append("embedding-server") print(f"Starting isolated services for {self.scenario}...", flush=True) self.compose("up", "-d", "--wait", *services, capture=False) self.postgres_port = self.service_port("postgres", 5432) - self.redis_port = self.service_port("redis", 6379) + self.redis_port = self.service_port("valkey", 6379) self.alertmanager_url = f"http://127.0.0.1:{self.service_port('alertmanager', 9093)}" if include_provider: self.embedding_port = self.service_port("embedding-server", 8000) diff --git a/scripts/local-services.sh b/scripts/local-services.sh index bdcf316c..39fb7e56 100755 --- a/scripts/local-services.sh +++ b/scripts/local-services.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -Eeuo pipefail -# DocGrid 로컬 실행에 필수인 Redis, Embedding Provider, Ollama의 기동과 준비 상태만 관리한다. +# DocGrid 로컬 실행에 필수인 Valkey, Embedding Provider, Ollama의 기동과 준비 상태만 관리한다. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" ACTION="${1:-status}" @@ -32,7 +32,7 @@ usage() { cat <<'EOF' Usage: ./scripts/local-services.sh - start Redis, Embedding Provider, Ollama를 기동하고 준비 완료까지 기다립니다. + start Valkey, Embedding Provider, Ollama를 기동하고 준비 완료까지 기다립니다. status 세 서비스의 실제 연결 상태와 Ollama 모델 준비 상태를 즉시 확인합니다. Environment: @@ -53,8 +53,8 @@ require_positive_integer() { fi } -redis_ready() { - docker compose exec -T redis redis-cli ping 2>/dev/null | grep -qx 'PONG' +valkey_ready() { + docker compose exec -T valkey valkey-cli ping 2>/dev/null | grep -qx 'PONG' } embedding_ready() { @@ -152,11 +152,11 @@ start_ollama() { print_status() { local failures=0 - # 1. 실행 상태가 아니라 실제 Redis 명령 응답으로 로그인 캐시 사용 가능 여부를 확인한다. - if redis_ready; then - ok "Redis 연결 가능" + # 1. 실행 상태가 아니라 실제 Valkey 명령 응답으로 로그인 캐시 사용 가능 여부를 확인한다. + if valkey_ready; then + ok "Valkey 연결 가능" else - fail "Redis 연결 실패 — 복구: docker compose up -d redis" + fail "Valkey 연결 실패 — 복구: docker compose up -d valkey" failures=$((failures + 1)) fi @@ -194,7 +194,7 @@ print_status() { return 1 fi - ok "Redis·Embedding Provider·Ollama가 모두 사용 가능합니다." + ok "Valkey·Embedding Provider·Ollama가 모두 사용 가능합니다." } start_services() { @@ -212,14 +212,14 @@ start_services() { } # 1. Compose 서비스는 기존 Volume을 유지한 채 필요한 두 서비스만 멱등하게 기동한다. - log "Redis와 Embedding Provider를 시작합니다." - COMPOSE_IGNORE_ORPHANS=true docker compose up -d redis embedding-server + log "Valkey와 Embedding Provider를 시작합니다." + COMPOSE_IGNORE_ORPHANS=true docker compose up -d valkey embedding-server # 2. Native Ollama를 기동해 Docker Desktop의 CPU 추론 경로를 피한다. start_ollama # 3. 각 서비스가 실제 요청을 받을 수 있을 때까지 제한 시간 안에서 기다린다. - wait_until_ready "Redis" redis_ready + wait_until_ready "Valkey" valkey_ready wait_until_ready "Embedding Provider" embedding_ready wait_until_ready "Ollama API" ollama_ready From 65d94572d975f3cc883922afcea732ef3a25e255 Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Sat, 3 Oct 2026 17:59:13 +0900 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20Valkey=20=EA=B5=90=EC=B2=B4=20?= =?UTF-8?q?=EC=95=88=EB=82=B4=EC=99=80=20=EC=84=A4=EA=B3=84=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C,=20=EA=B2=80=EC=A6=9D=20=EC=A6=9D=EA=B1=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#399)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README: 기술 스택 표기를 Valkey 9.1(Redis 프로토콜 호환, 클라이언트 Spring Data Redis)로 변경하고 compose 명령어의 서비스명을 valkey로 변경 - .env.example: Valkey 사용과 변수명 REDIS_* 유지 이유를 안내 - docs/design: 배경, 결정, 변경 범위, 검증 결과, 재현·롤백 방법, 레포 밖 확인 사항 정리 - docs/test-results/evidence/issue-399: Redis 7.4.10과 Valkey 9.1.2의 전체 테스트 220개 클래스별 결과표, verify.sh --e2e 출력, 집계 스크립트 Co-Authored-By: Claude Sonnet 5.5 --- .env.example | 3 +- README.md | 16 +- .../kangcheolung-#399-valkey-migration.md | 287 ++++++++++++++++++ .../issue-399/full-redis-7.4.10-summary.txt | 221 ++++++++++++++ .../issue-399/full-valkey-9.1.2-summary.txt | 221 ++++++++++++++ .../evidence/issue-399/summarize.py | 15 + .../evidence/issue-399/verify-e2e.log | 205 +++++++++++++ 7 files changed, 959 insertions(+), 9 deletions(-) create mode 100644 docs/design/kangcheolung-#399-valkey-migration.md create mode 100644 docs/test-results/evidence/issue-399/full-redis-7.4.10-summary.txt create mode 100644 docs/test-results/evidence/issue-399/full-valkey-9.1.2-summary.txt create mode 100644 docs/test-results/evidence/issue-399/summarize.py create mode 100644 docs/test-results/evidence/issue-399/verify-e2e.log diff --git a/.env.example b/.env.example index 08723fe8..1c00552e 100644 --- a/.env.example +++ b/.env.example @@ -90,8 +90,9 @@ MINIO_SECRET_KEY=minioadmin1234 # OLLAMA_SERVER_CONNECT_TIMEOUT=3s # OLLAMA_SERVER_READ_TIMEOUT=18s -# Redis (로그아웃 토큰 블랙리스트) - application.yml에 이미 기본값(localhost:6379, 인증 없음)이 있어 +# Valkey (로그아웃 토큰 블랙리스트) - application.yml에 이미 기본값(localhost:6379, 인증 없음)이 있어 # docker-compose 기본 포트를 쓰면 설정 불필요. 기본값과 다를 때만 주석 해제 +# Valkey는 Redis 프로토콜과 호환되고 Spring Data Redis가 접속하므로 변수명은 REDIS_*를 그대로 사용합니다. # REDIS_HOST=localhost # REDIS_PORT=6379 # REDIS_PASSWORD= diff --git a/README.md b/README.md index a69915ce..2c76712d 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ DocGrid는 조직에 흩어진 PDF·DOCX 문서를 자동으로 인덱싱하고, | Database | OpenSQL 17.8, PostgreSQL 17, pgvector 0.8.1 | | AI | BAAI/bge-m3, Ollama, qwen2.5:7b | | Storage | Local Filesystem, MinIO, AWS S3 | -| Cache | Redis 7 | +| Cache | Valkey 9.1 (Redis 프로토콜 호환, 클라이언트: Spring Data Redis) | | Observability | RAGOps Dashboard, Prometheus | | Test | JUnit 5, Gradle, Node.js Test Runner | @@ -69,10 +69,10 @@ npm --prefix frontend install `.env.example`은 로컬 PostgreSQL, MinIO와 자동 인덱싱 Worker를 실행할 수 있는 기본값을 제공합니다. 실제 비밀번호와 외부 서버 인증정보는 `.env`, README, Issue 또는 Commit에 기록하지 않습니다. -### 3. PostgreSQL, MinIO, Redis, BGE-M3 실행 +### 3. PostgreSQL, MinIO, Valkey, BGE-M3 실행 ```bash -docker compose up -d --build postgres minio redis embedding-server +docker compose up -d --build postgres minio valkey embedding-server docker compose logs -f embedding-server ``` @@ -96,7 +96,7 @@ ollama pull qwen2.5:7b ollama run qwen2.5:7b "안녕" ``` -초기 설치 후에는 Redis, BGE-M3, Ollama를 전용 스크립트로 한 번에 기동하고 실제 연결 상태까지 확인합니다. +초기 설치 후에는 Valkey, BGE-M3, Ollama를 전용 스크립트로 한 번에 기동하고 실제 연결 상태까지 확인합니다. ```bash ./scripts/local-services.sh start @@ -147,7 +147,7 @@ Embedding Provider가 준비되지 않아도 먼저 기동해 수집 실패와 ### 종료 ```bash -docker compose stop postgres minio redis embedding-server +docker compose stop postgres minio valkey embedding-server # macOS에서 Homebrew로 Ollama를 실행한 경우 brew services stop ollama ``` @@ -180,11 +180,11 @@ SSH Key는 저장소에 포함하지 않습니다. 환경별 설정은 [.env.exa ## 테스트 -일반 회귀 테스트는 외부 장시간 Benchmark와 실제 인프라 E2E를 제외하지만 PostgreSQL과 Redis를 +일반 회귀 테스트는 외부 장시간 Benchmark와 실제 인프라 E2E를 제외하지만 PostgreSQL과 Valkey를 사용하는 통합 테스트를 포함합니다. 두 Service를 먼저 준비합니다. ```bash -docker compose up -d --wait postgres redis +docker compose up -d --wait postgres valkey ./backend/gradlew -p backend test npm --prefix frontend test ``` @@ -192,7 +192,7 @@ npm --prefix frontend test 파일 저장소 Adapter와 실제 자동 Worker 전체 흐름은 별도 E2E로 검증합니다. ```bash -docker compose up -d --build --wait postgres minio redis embedding-server +docker compose up -d --build --wait postgres minio valkey embedding-server DB_HOST=127.0.0.1 DB_PORT=55432 \ ./backend/gradlew -p backend storageWorkerE2eTest diff --git a/docs/design/kangcheolung-#399-valkey-migration.md b/docs/design/kangcheolung-#399-valkey-migration.md new file mode 100644 index 00000000..bcb27a7a --- /dev/null +++ b/docs/design/kangcheolung-#399-valkey-migration.md @@ -0,0 +1,287 @@ +# #399 캐시 서버를 Redis 7.4에서 Valkey로 교체 + +closes #399 + +--- + +## 배경 + +대회의 오픈소스 라이선스 평가 기준(OSI 승인 라이선스)에 비추어 보면, 로컬·테스트용 compose가 실행하는 캐시 서버가 문제였다. + +- `docker-compose.yml`은 `redis:7-alpine`을 썼다. 이 태그는 7 메이저의 **최신**을 따라가므로 실제로는 **Redis 7.4.10**이 실행됐다. (직접 확인: `redis-server --version` → `v=7.4.10`) +- Redis 7.4.x의 라이선스는 RSALv2 / SSPLv1이며 OSI 승인을 받지 못했다. (팀에서 공유받은 정리 자료 기준) +- 평가는 각 평가 시점의 저장소 상태로 이루어지고 2차 평가는 10/12~10/28이므로, 그 전에 반영해야 한다. + +| 선택지 | 라이선스 | OSI 승인 | +|---|---|---| +| Redis 7.2.x 이하 | BSD-3-Clause | 승인 | +| **Redis 7.4.x (기존 compose)** | RSALv2 / SSPLv1 | **미승인** | +| Redis 8.x | RSALv2 / SSPLv1 / AGPLv3 중 택1 | AGPLv3 선택 시 승인 | +| **Valkey (채택)** | BSD-3-Clause | 승인 | + +> 문제가 된 것은 "Redis"라는 이름이 아니라 **Redis 7.4 서버 프로그램의 라이선스**다. 서버와 통신하는 클라이언트 라이브러리는 별개의 소프트웨어이며 아래와 같이 라이선스 문제가 없다. + +| 구성요소 | 역할 | 라이선스 | 확인 방법 | +|---|---|---|---| +| Valkey | 캐시 서버 | BSD-3-Clause | 공식 저장소(valkey-io/valkey)에 명시, LF Projects 거버넌스 | +| Spring Data Redis | 자바 클라이언트(`StringRedisTemplate` 등) | Apache 2.0 | 공식 저장소(spring-projects/spring-data-redis)에 명시 | +| Lettuce 6.6.0 | 실제 접속 엔진 | MIT | 이 프로젝트가 내려받은 POM의 `` | + +--- + +## 결정 + +**서버 프로그램만 Valkey로 교체한다. 클라이언트 라이브러리·설정·환경변수·자바 코드는 바꾸지 않는다.** + +Valkey는 Redis 7.2.4에서 갈라져 나온 포크로 같은 Redis 프로토콜(RESP)을 구현한다. 실제로 Valkey에 `INFO server`를 요청하면 호환용으로 `redis_version:7.2.4`를 함께 보고한다(`valkey_version:9.1.2`, `server_name:valkey`). + +```text +앱(자바) + └─ Spring Data Redis / Lettuce ← 유지 (Redis 프로토콜로 말하는 클라이언트) + └─ spring.data.redis.*, REDIS_* 환경변수 ← 유지 + └─ 서버: Redis 7.4 → Valkey 9.1 ← 이번에 교체 +``` + +### 이름을 유지하는 것 + +| 이름 | 위치 | 유지 이유 | +|---|---|---| +| `StringRedisTemplate`, `RedisScript`, `RedisMessageListenerContainer` | 자바 코드 3곳 | Spring Data Redis 라이브러리의 클래스. 우리가 바꿀 수 없다 | +| `spring.data.redis.*` | `application.yml` | Spring Boot가 이 이름으로 접속 설정을 읽는다. 지우면 접속 정보를 읽지 못한다 | +| `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD` 등 | `application.yml`, compose, 스크립트 | GCP A/B 환경 등 레포 밖 배포 설정이 이 이름에 의존한다. 일관성을 위해 바꾸려면 인프라 담당과 같이 바꿔야 해서 이번 범위에서 제외 | + +### 선택하지 않은 방법 + +- **Redis 7.2로 고정**: BSD라 통과하지만 구버전에 묶이는 것이어서 Valkey보다 나은 점이 없다. +- **Redis 8 + AGPLv3**: 기준은 통과하지만 Apache-2.0 프로젝트에 AGPL 구성요소를 섞는 설명 부담이 생긴다. +- **Spring Data Valkey(valkey-io, Apache 2.0)로 클라이언트까지 교체**: `spring-boot-starter-data-valkey` 의존성과 `StringValkeyTemplate` 등 클래스명 변경으로 코드 3곳을 고쳐야 한다. 라이선스 문제는 서버에만 있어 얻는 이득이 이름 통일뿐이고, 이 프로젝트의 Spring Boot 3.5와의 호환은 확인하지 못했다. 필요하면 별도 이슈로 검토한다. + +--- + +## 변경 범위 + +### 변경한 파일 + +| 파일 | 변경 | +|---|---| +| `docker-compose.yml` | 서비스 `redis` → `valkey`, 이미지 `redis:7-alpine` → `valkey/valkey:9.1-alpine`(마이너까지 고정), 컨테이너 `docgrid-valkey`, 볼륨 `valkey-data`, healthcheck `valkey-cli ping` | +| `monitoring/drills/docker-compose.yml` | 서비스·이미지·healthcheck 동일 변경 | +| `monitoring/drills/run_drill.py` | 서비스명 참조 2곳(`start_core`의 서비스 목록, `service_port("valkey", 6379)`) | +| `scripts/local-services.sh` | `valkey_ready`(`docker compose exec -T valkey valkey-cli ping`), `up -d valkey`, 안내 문구 | +| `README.md` | 기술 스택 표(`Valkey 9.1 (Redis 프로토콜 호환, 클라이언트: Spring Data Redis)`), compose 명령어와 안내 문구 7곳 | +| `.env.example` | Valkey 사용 및 변수명 `REDIS_*` 유지 이유 설명 | + +호스트 포트 매핑 변수는 `${REDIS_PORT:-6379}` 그대로이므로 기존 환경 설정이 유지된다. + +### 변경하지 않은 것 + +- 자바 코드, `application.yml`, `build.gradle` 의존성(`spring-boot-starter-data-redis`) +- `docs/test-results/**`: 과거에 실제 Redis로 시험한 기록이라 소급 수정하지 않는다. 수정하면 증거가 왜곡된다. +- `docs/design/**`의 기존 설계 문서: "Redis 캐시", "Redis blacklist"는 프로토콜/기능 이름으로 여전히 유효하다. +- `scripts/opensql/*.py`: Redis 프로토콜을 소켓으로 직접 말하는 구현이라 서버 종류와 무관하다. + +--- + +## 호환성 근거 + +이 프로젝트가 Redis 서버에 쓰는 기능은 아래뿐이며 모두 Valkey가 지원한다. + +| 기능 | 사용처 | +|---|---| +| `SET` + TTL, `GET`, `MGET`, `DEL` | `TokenBlacklistService`(로그아웃 토큰 블랙리스트), `RoleAuthorityService`(역할 캐시) | +| Lua `EVAL`/`EVALSHA` | `RoleAuthorityService`의 캐시 무효화·조건부 캐시 스크립트 | +| Pub/Sub (`PUBLISH`/`SUBSCRIBE`) | `DashboardCrossNodeSignal`(두 백엔드 사이 대시보드 갱신 신호) | + +--- + +## 검증 + +### 환경 (개발 DB와 완전히 분리) + +| 항목 | 값 | +|---|---| +| 기준선 서버 | `redis:7-alpine` = Redis 7.4.10 (임시 컨테이너, 호스트 16379) | +| 전환 후 서버 | **변경한 `docker-compose.yml`의 `valkey` 서비스** = Valkey 9.1.2, 이미지 `valkey/valkey:9.1-alpine`(digest `sha256:48332870af35...`), 호스트 16379 | +| DB | 임시 `pgvector/pgvector:0.8.1-pg17` (호스트 55432, DB `app`), 테스트 스키마 `docgrid_test` | +| 접속 정보 | `DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASSWORD`, `REDIS_HOST/REDIS_PORT`, `DOCGRID_TEST_REDIS_PORT`를 환경변수로 덮어씀 | + +기준선과 전환 후는 서버만 다르고 DB·테스트 설정·명령이 같다. + +### 결과: Redis 관련 테스트 7개 클래스 + +| 테스트 | 종류 | 테스트 수 | Redis 7.4.10 | Valkey 9.1.2 | +|---|---|---|---|---| +| `StompDashboardRealRoleRevocationIntegrationTest` | 실제 서버(Lua `EVAL`, 캐시 무효화) | 4 | 통과 | 통과 | +| `DashboardCrossNodeSignalRedisIntegrationTest` | 실제 서버(Pub/Sub, 재구독) | 1 | 통과 | 통과 | +| `DashboardCrossNodeWebSocketIntegrationTest` | 실제 서버(앱 2대 + Pub/Sub + STOMP) | 1 | 통과 | 통과 | +| `ManagementEndpointIntegrationTest` | 서버 없이(Redis 장애 시 fail-open) | 4 | 통과 | 통과 | +| `RoleAuthorityServiceTest` | 단위(mock) | 6 | 통과 | 통과 | +| `TokenBlacklistServiceTest` | 단위(mock) | 5 | 통과 | 통과 | +| `DashboardCrossNodeSignalTest` | 단위(mock) | 4 | 통과 | 통과 | +| **합계** | | **25** | **실패 0, 건너뜀 0** | **실패 0, 건너뜀 0** | + +### 결과: 전체 테스트 + +| | Redis 7.4.10 | Valkey 9.1.2 | +|---|---|---| +| `./backend/gradlew -p backend test` | 1297개 통과 | 1297개 통과 | +| 실패 / 에러 / 건너뜀 | 0 / 0 / 0 | 0 / 0 / 0 | +| 클래스별 결과 | — | 기준선과 **완전히 동일** | + +전체 220개 테스트 클래스의 클래스별 결과는 기준선·전환 후가 파일 단위로 **차이 없음**(`diff` 결과 빈 출력)이다. 원본은 아래 증거 파일에 있다. + +| 증거 파일 | 내용 | +|---|---| +| [full-redis-7.4.10-summary.txt](../test-results/evidence/issue-399/full-redis-7.4.10-summary.txt) | 기준선(Redis 7.4.10) 전체 220개 클래스별 tests/fail/err/skipped | +| [full-valkey-9.1.2-summary.txt](../test-results/evidence/issue-399/full-valkey-9.1.2-summary.txt) | 전환 후(Valkey 9.1.2) 동일 집계 | +| [verify-e2e.log](../test-results/evidence/issue-399/verify-e2e.log) | `./monitoring/verify.sh --e2e` 출력 | +| [summarize.py](../test-results/evidence/issue-399/summarize.py) | Gradle XML 리포트(`build/test-results/test`)를 클래스별로 집계하는 스크립트 | + +### Redis 관련 테스트 케이스 상세 (25개, 기준선·전환 후 모두 통과) + +소요 시간은 `Redis 7.4.10 / Valkey 9.1.2` 순서이며 전체 실행 중 측정한 값이다. + +**`StompDashboardRealRoleRevocationIntegrationTest`** — 실제 서버(역할 캐시 Lua 무효화, 실제 HTTP·DB·STOMP) + +| 케이스 | 시간 | +|---|---| +| 권한 확인을 마친 진행 중 메시지는 회수 응답 뒤에도 도착할 수 있다 | 0.98s / 0.97s | +| HTTP 역할 회수 뒤 주기 재검증 없이 새 구독과 기존 구독 push가 차단된다 | 0.75s / 0.75s | +| 실제 발행 코드의 primary 판정은 outbound에 남고 STOMP 클라이언트에는 노출되지 않는다 | 0.18s / 0.17s | +| Redis 무효화 실패로 낡은 ADMIN 캐시가 남아도 새 대시보드 push를 차단한다 | 0.60s / 0.59s | + +**`DashboardCrossNodeSignalRedisIntegrationTest`** — 실제 서버(Pub/Sub) + +| 케이스 | 시간 | +|---|---| +| A/B 신호가 반대편에만 도착하고 재구독 시 놓친 상태를 다시 읽는다 | 0.33s / 0.39s | + +**`DashboardCrossNodeWebSocketIntegrationTest`** — 실제 서버(독립 Spring 앱 2대 + Pub/Sub + STOMP 구독) + +| 케이스 | 시간 | +|---|---| +| A/B 어느 쪽만 발행해도 반대편은 자기 DB 요약을 다시 계산해 자기 관리자에게 보낸다 | 4.79s / 5.23s | + +**`ManagementEndpointIntegrationTest`** — 서버 없이(연결 불가 포트로 Redis 장애 재현) + +| 케이스 | 시간 | +|---|---| +| health probe와 Prometheus는 Management 포트에서 인증 없이 조회한다 | 0.04s / 0.04s | +| Prometheus 출력에 JVM, HTTP 서버, HikariCP 메트릭이 포함된다 | 0.02s / 0.02s | +| Redis를 사용할 수 없어도 DB가 정상이면 readiness는 UP이다 | 1.05s / 1.05s | +| 민감한 Actuator 엔드포인트와 애플리케이션 포트의 Actuator 경로는 노출하지 않는다 | 0.02s / 0.01s | + +**단위 테스트(mock)** — Redis 서버에 접속하지 않으므로 호환성 검증이 아닌 회귀 확인용이다. + +| 클래스 | 케이스 | +|---|---| +| `RoleAuthorityServiceTest` (6) | Redis 조회 실패 시 DB 폴백 / DB 조회 중 권한 변경 시 오래된 역할 미반환·미캐시 / 관리자 요청은 캐시를 읽지 않고 primary 조회 / 무효화 후 DB 재조회 / 캐시 히트 시 DB 미조회 / 캐시 미스 시 DB 조회 후 캐싱 | +| `TokenBlacklistServiceTest` (5) | MGET 응답이 불완전하면 실패 / 등록된 jti는 true / 여러 jti를 MGET 한 번으로 조회 / 미등록 jti는 false / 남은 만료 시간만큼 TTL로 저장 | +| `DashboardCrossNodeSignalTest` (4) | 재구독 시 놓친 변경 재조회 표시 / 비활성·발행 오류가 로컬 push를 실패시키지 않음 / 고정 채널에 인스턴스 ID만 발행하고 자기 echo 무시 / 다른 백엔드 신호는 원격 dirty만 세우고 재발행하지 않음 | + +### 실행 이력 + +시행착오를 포함해 실제로 실행한 순서다. 1~2번은 환경 격리가 불완전했던 시험 실행이고, 3번부터가 비교에 쓴 측정이다. + +| # | 서버 | DB | 범위 | 결과 | 소요 | +|---|---|---|---|---|---| +| 1 | Redis 7.4.10 | `backend/.env`의 개발 DB(`docgrid_test` 스키마) | 7개 클래스 | 25개 중 24 통과, **1 건너뜀** (`DashboardCrossNodeWebSocketIntegrationTest`: `DB_PORT` 미지정으로 `assumeTrue` 건너뜀) | 32s | +| 2 | Redis 7.4.10 | 임시 PostgreSQL을 가리키도록 `DB_PORT`만 지정 | 7개 클래스 | **5 실패** (STOMP 4 + A/B 앱 1). 원인: 환경변수로 덮어쓰지 않은 `DB_USER` 등이 `backend/.env`의 개발용 값으로 적용되어 임시 DB에서 인증 실패 → Flyway/컨텍스트 로딩 실패. Redis와 무관 | 14s | +| 3 | Redis 7.4.10 | 임시 PostgreSQL, 접속 정보 전부 덮어씀 | 7개 클래스 | **25 통과**, 건너뜀 0 | 22s | +| 4 | Redis 7.4.10 | 임시 PostgreSQL | 전체 | **1297 통과**, 건너뜀 0 | 1m 40s | +| 5 | **Valkey 9.1.2** | 임시 PostgreSQL | 7개 클래스 | **25 통과**, 건너뜀 0 | 23s | +| 6 | **Valkey 9.1.2** | 임시 PostgreSQL | 전체 | **1297 통과**, 건너뜀 0 | 1m 37s | +| 7 | — | — | `./monitoring/verify.sh --e2e` | 통과 | — | + +### Valkey가 실제로 호출됐는지 (서버 명령 통계, 컨테이너 시작 후 누적) + +| 명령 | 호출 수 | 비고 | +|---|---|---| +| `EVAL` | 2 | 스크립트 최초 로드 | +| `EVALSHA` | 18 | 이 중 `failed_calls=2` | +| `SUBSCRIBE` / `PUBLISH` | 10 / 10 | 대시보드 Pub/Sub | +| `GET` / `MGET` / `SET` / `DEL` | 70 / 17 / 23 / 36 | 블랙리스트·역할 캐시 | +| 전체 오류 응답 | 2 | `EVALSHA` 실패 2건뿐 | + +`EVALSHA`의 실패 2건은 `EVAL` 호출 2건과 짝이 맞는다. Spring이 스크립트를 처음 실행할 때 `EVALSHA`를 먼저 시도하고, 서버에 스크립트가 없어 오류(`NOSCRIPT`)가 나면 `EVAL`로 다시 보내는 정상 동작으로 해석된다. 그 외 오류 응답은 없다. + +### 그 외 확인 + +| 항목 | 결과 | +|---|---| +| `docker compose up -d --wait valkey` | healthy (healthcheck `valkey-cli ping`) | +| `./scripts/local-services.sh status` | `Valkey 연결 가능` (Embedding Provider 실패는 아래 "발견한 사항" 참고, 이번 변경과 무관) | +| drill compose의 `valkey` 단독 기동 | healthy, `docker compose port valkey 6379`로 동적 포트 조회 성공 (`run_drill.py`가 쓰는 방식) | +| 이미지 확인 | Docker Hub에 `valkey/valkey:9.1-alpine` 태그 존재(마지막 갱신 2026-09-21), `valkey-server --version` = 9.1.2, 이미지에 `valkey-cli`와 호환용 `redis-cli`가 모두 포함(healthcheck·스크립트는 `valkey-cli` 사용) | +| `INFO server` 응답 | `redis_version:7.2.4`(호환용), `valkey_version:9.1.2`, `server_name:valkey` | +| `docker compose config -q` (루트·drill) | 통과 | +| `bash -n scripts/local-services.sh`, `py_compile run_drill.py` | 통과 | +| `./monitoring/verify.sh --e2e` (CI와 동일) | 통과 (`Monitoring configuration validation: SUCCESS`, Alertmanager routing E2E 성공) | + +--- + +## 검증 중 발견한 사항 + +1. **CI는 Redis 컨테이너를 실제로 띄우지 않는다.** `monitoring-validation.yml`이 실행하는 `verify.sh --e2e`는 drill compose를 `config --quiet`로 렌더링만 한다. 그래서 이 변경이 CI에서 확인되는 것은 "compose가 올바르게 렌더링되는가"까지다. 실제 Valkey 동작은 위 로컬 검증으로 확인했다. +2. **로컬 6379 포트의 Redis는 Docker가 아니라 Homebrew `redis-server` 8.4.0이다.** 호스트 프로세스(5월 22일부터)이고, compose의 `docgrid-redis` 컨테이너는 한 번도 시작되지 않은 `Created` 상태였다. 즉 개발자 로컬 앱은 compose가 아닌 Homebrew Redis에 붙고 있었다. Redis 8.x는 RSALv2/SSPLv1/AGPLv3 중 택1이다. 저장소 산출물이 아니라 개인 PC 환경이지만, 로컬 앱을 Valkey로 돌리려면 `brew services stop redis`로 멈추거나 `REDIS_PORT`를 바꿔야 6379 충돌이 없다. +3. **`application.yml`이 `backend/.env`를 불러온다(`spring.config.import: optional:file:.env[.properties]`).** 테스트 실행 시 환경변수로 덮어쓰지 않은 값은 개발용 DB 설정으로 접속한다. 이번 검증의 첫 시험 실행이 그랬고, 개발 DB의 `docgrid_test` 스키마에 아직 적용되지 않았던 Flyway 마이그레이션 1건이 적용됐다(`public` 스키마의 개발 데이터는 건드리지 않았고 테스트 잔여 데이터도 없음). 이후 모든 측정은 DB·Redis 접속 정보를 전부 환경변수로 덮어써 임시 컨테이너만 사용했다. +4. **로컬 `docgrid-embedding` 컨테이너 이미지가 오래됐다(2026-08-15 빌드).** `local-services.sh`가 호출하는 `/health/ready`가 없어(404) `status`가 Embedding Provider를 "준비 안 됨"으로 표시한다. 소스(`backend/embedding-server/main.py`)에는 해당 경로가 있으므로 컨테이너 재빌드로 해결되며 이번 변경과 무관하다. +5. **Pub/Sub 통합 테스트는 환경변수 없이는 건너뛴다.** `DashboardCrossNodeSignalRedisIntegrationTest`는 `DOCGRID_TEST_REDIS_PORT`, `DashboardCrossNodeWebSocketIntegrationTest`는 거기에 `DB_PORT`까지 있어야 실행된다. 없으면 `assumeTrue`로 조용히 건너뛰어 통과처럼 보이므로, 검증 시 "건너뜀 0"을 확인해야 한다. (처음 실행에서 이 테스트가 건너뛰어졌고 환경변수를 추가해 해결했다.) +6. **`minio/minio` 이미지는 태그가 없는 `latest`다.** 이번 Redis 건과 같은 유형(떠다니는 태그)이다. 로컬에는 13개월 된 이미지가 캐시되어 있어 동작하지만, 새 환경에서 `docker pull minio/minio`가 되는지는 확인하지 못했다(Docker Hub API 조회는 "not found"를 반환했으나 이것만으로 단정할 수 없음). 별도로 확인이 필요하다. + +--- + +## 이 PR 밖에서 확인할 것 + +| 항목 | 내용 | 담당 | +|---|---|---| +| GCP A/B 공용 Redis VM | Rocky Linux 9.8 VM에 systemd 서비스 `redis`로 설치되어 있다(`docs/test-results/evidence/issue-380`, `issue-382` 참고). 설치 출처와 버전은 문서에 없다. `redis-server --version`으로 확인하고, 7.4 이상이면 Valkey로 교체한 뒤 A/B 시험(#382 시나리오)을 다시 확인해야 한다 | 인프라 담당 팀원 | +| 8/27 제출 SBOM | Redis 항목의 표기·버전·라이선스가 실제(7.4.x, RSALv2/SSPLv1)와 다르게 적혀 있다면 정정본을 레포에 올린다 | SBOM 제출 담당 | +| 운영규정 원문 | 평가 기준이 정말 OSI 승인인지, 이름에 Redis가 들어간 구성요소(클라이언트 라이브러리, 환경변수)가 문제가 되지 않는지 확인한다. 불확실하면 운영사무국에 문의한다 | 팀 | +| 서비스명 변경 공지 | `docker compose up -d redis`를 쓰던 팀원은 `valkey`로 바꿔야 한다 | 팀 전체 | + +--- + +## 팀원 로컬 전환 방법 + +```bash +# 이전 redis 서비스를 대체합니다 +docker compose up -d --wait valkey + +# 선택: 더 이상 쓰지 않는 기존 컨테이너·볼륨 정리 (블랙리스트·역할 캐시만 있어 지워도 됩니다) +docker rm docgrid-redis +docker volume rm docgrid_redis-data +``` + +6379 포트를 Homebrew `redis-server`가 쓰고 있다면 먼저 `brew services stop redis`로 멈추거나 `REDIS_PORT`를 다른 값으로 지정합니다. + +--- + +## 재현 방법 + +```bash +# 1) 개발 DB와 분리된 임시 DB (테스트 스키마는 Flyway가 만든다) +docker run -d --name docgrid-399-pg -p 127.0.0.1:55432:5432 \ + -e POSTGRES_DB=app -e POSTGRES_USER=app -e POSTGRES_PASSWORD=local_password \ + -v "$PWD/docker/postgres/init/001-enable-vector.sql:/docker-entrypoint-initdb.d/001-enable-vector.sql:ro" \ + pgvector/pgvector:0.8.1-pg17 + +# 2) 전환 후 서버 (변경한 compose 사용, 호스트 포트만 변경) +REDIS_PORT=16379 docker compose up -d --wait valkey + +# 3) 전체 테스트: DB·Redis 접속 정보를 모두 환경변수로 덮어써 backend/.env의 개발 DB를 쓰지 않게 한다 +DB_HOST=127.0.0.1 DB_PORT=55432 DB_NAME=app DB_USER=app DB_PASSWORD=local_password \ +REDIS_HOST=127.0.0.1 REDIS_PORT=16379 DOCGRID_TEST_REDIS_PORT=16379 \ + ./backend/gradlew -p backend cleanTest test + +# 4) 서버가 실제로 쓰였는지 확인 +docker exec docgrid-valkey valkey-cli INFO commandstats +``` + +기준선은 2)에서 `valkey` 대신 `docker run -d -p 127.0.0.1:16379:6379 redis:7-alpine`을 띄워 같은 3)을 실행했다. + +--- + +## 롤백 + +이미지 태그와 이름을 되돌리면 된다(`git revert`). Valkey 볼륨(`valkey-data`)과 기존 Redis 볼륨(`redis-data`)에는 로그아웃 토큰 블랙리스트와 역할 캐시만 있어 데이터 손실 영향이 없다. 두 값 모두 만료되거나 DB에서 다시 채워진다. diff --git a/docs/test-results/evidence/issue-399/full-redis-7.4.10-summary.txt b/docs/test-results/evidence/issue-399/full-redis-7.4.10-summary.txt new file mode 100644 index 00000000..da64987a --- /dev/null +++ b/docs/test-results/evidence/issue-399/full-redis-7.4.10-summary.txt @@ -0,0 +1,221 @@ +DocgridApplicationTests tests=1 fail=0 err=0 skipped=0 +SignupRequest 테스트 tests=3 fail=0 err=0 skipped=0 +로그아웃 PostgreSQL·Redis 통합 테스트 tests=1 fail=0 err=0 skipped=0 +STOMP 연결 인증 통합 테스트 tests=4 fail=0 err=0 skipped=0 +STOMP 실제 역할 회수 통합 테스트 tests=4 fail=0 err=0 skipped=0 +STOMP 관리자 권한 회수 경계 통합 테스트 tests=3 fail=0 err=0 skipped=0 +STOMP 목적지 인가 통합 테스트 tests=5 fail=0 err=0 skipped=0 +STOMP 세션 수명주기 통합 테스트 tests=4 fail=0 err=0 skipped=0 +JwtAuthenticationFilter 단위 테스트 tests=5 fail=0 err=0 skipped=0 +JwtProviderTest tests=1 fail=0 err=0 skipped=0 +RoleAuthorityService 단위 테스트 tests=6 fail=0 err=0 skipped=0 +StompAuthChannelInterceptor 단위 테스트 tests=11 fail=0 err=0 skipped=0 +TokenBlacklistService 단위 테스트 tests=5 fail=0 err=0 skipped=0 +AuthCommandService 단위 테스트 tests=14 fail=0 err=0 skipped=0 +AuthQueryService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +PrimaryRoleQueryService 단위 테스트 tests=7 fail=0 err=0 skipped=0 +STOMP 대시보드 outbound 인가 단위 테스트 tests=7 fail=0 err=0 skipped=0 +STOMP 목적지 인가 Interceptor 단위 테스트 tests=22 fail=0 err=0 skipped=0 +STOMP 세션 Registry 단위 테스트 tests=5 fail=0 err=0 skipped=0 +STOMP 세션 재검증 Scheduler 단위 테스트 tests=7 fail=0 err=0 skipped=0 +CollectionController 테스트 tests=5 fail=0 err=0 skipped=0 +컬렉션 트리 Repository 테스트 tests=16 fail=0 err=0 skipped=0 +CollectionCommandService 단위 테스트 tests=25 fail=0 err=0 skipped=0 +CollectionQueryService 단위 테스트 tests=14 fail=0 err=0 skipped=0 +대시보드 WebSocket 발행 권한 일괄 조회 단위 테스트 tests=4 fail=0 err=0 skipped=0 +대시보드 교차 백엔드 Redis Pub/Sub 통합 테스트 tests=1 fail=0 err=0 skipped=0 +대시보드 교차 백엔드 갱신 신호 단위 테스트 tests=4 fail=0 err=0 skipped=0 +대시보드 A/B Spring 앱·WebSocket 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Dashboard push debounce burst 통합 테스트 tests=1 fail=0 err=0 skipped=0 +DashboardPushScheduler 단위 테스트 tests=7 fail=0 err=0 skipped=0 +DashboardUpdateFlag 단위 테스트 tests=4 fail=0 err=0 skipped=0 +Embedding Job 상태 전이 이벤트 AFTER_COMMIT 통합 테스트 tests=2 fail=0 err=0 skipped=0 +EmbeddingJobStatusChangedEventListener 단위 테스트 tests=1 fail=0 err=0 skipped=0 +EmbeddingJobRetryService 단위 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJobRetryService 트랜잭션 독립성 통합 테스트 tests=1 fail=0 err=0 skipped=0 +대시보드 집계 SQL 개수 통합 테스트 tests=1 fail=0 err=0 skipped=0 +DashboardQueryService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +Dashboard WebSocket 실시간 push 통합 테스트 tests=4 fail=0 err=0 skipped=0 +Chunk Size·Overlap 품질 Benchmark 계약 테스트 tests=9 fail=0 err=0 skipped=0 +DocumentChunkingProperties 테스트 tests=3 fail=0 err=0 skipped=0 +문서 업로드 제한 설정 테스트 tests=1 fail=0 err=0 skipped=0 +FileStorageProperties 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentCommandController 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentQueryController 테스트 tests=10 fail=0 err=0 skipped=0 +DocumentUploadController 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentDetailConverter 테스트 tests=1 fail=0 err=0 skipped=0 +DocumentStatusConverter 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentVersionHistoryConverter 단위 테스트 tests=1 fail=0 err=0 skipped=0 +Document 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentVersion 테스트 tests=29 fail=0 err=0 skipped=0 +Document Chunking OpenSQL 통합 테스트 tests=5 fail=0 err=0 skipped=0 +문서 업로드 통합 테스트 tests=4 fail=0 err=0 skipped=0 +문서 새 버전 업로드 통합 테스트 tests=4 fail=0 err=0 skipped=0 +S3 저장소 Spring Context 통합 테스트 tests=1 fail=0 err=0 skipped=0 +읽기 가능 문서 ID Repository 테스트 tests=7 fail=0 err=0 skipped=0 +findByIdWithCurrentVersion 테스트 tests=2 fail=0 err=0 skipped=0 +문서 상태 Projection Repository 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentFileService 테스트 tests=2 fail=0 err=0 skipped=0 +DocumentParserRegistry 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentParsingService 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentUploadFacade 단위 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentVersionUploadFacade 단위 테스트 tests=6 fail=0 err=0 skipped=0 +DocxDocumentParser 테스트 tests=3 fail=0 err=0 skipped=0 +FileHashService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +FileValidationService 단위 테스트 tests=12 fail=0 err=0 skipped=0 +FixedSizeChunker 테스트 tests=10 fail=0 err=0 skipped=0 +PdfDocumentParser 테스트 tests=10 fail=0 err=0 skipped=0 +TextDocumentParser 테스트 tests=6 fail=0 err=0 skipped=0 +DocumentChunkTransactionService 테스트 tests=10 fail=0 err=0 skipped=0 +DocumentCommandService 단위 테스트 tests=8 fail=0 err=0 skipped=0 +DocumentUploadService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentVersionUploadService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +FileObjectResolutionService 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentQueryService 테스트 tests=19 fail=0 err=0 skipped=0 +GcsStorageService 테스트 tests=7 fail=0 err=0 skipped=0 +LocalFileStorageService 테스트 tests=6 fail=0 err=0 skipped=0 +MinioStorageService 테스트 tests=6 fail=0 err=0 skipped=0 +S3StorageService 테스트 tests=8 fail=0 err=0 skipped=0 +실제 PDF Embedding Corpus Exporter 테스트 tests=1 fail=0 err=0 skipped=0 +Vector 저장 Benchmark 지원 계약 tests=6 fail=0 err=0 skipped=0 +EmbeddingClient 단위 테스트 tests=19 fail=0 err=0 skipped=0 +EmbeddingProviderCircuitBreaker 테스트 tests=7 fail=0 err=0 skipped=0 +EmbeddingBatchProperties 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingProviderCircuitBreakerProperties 테스트 tests=2 fail=0 err=0 skipped=0 +EmbeddingModelController 테스트 tests=3 fail=0 err=0 skipped=0 +IndexingJobAdminController 테스트 tests=104 fail=0 err=0 skipped=0 +IndexingJobAdminController 조회 테스트 tests=17 fail=0 err=0 skipped=0 +EmbeddingJobAttemptConverter 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingJobConverter 테스트 tests=1 fail=0 err=0 skipped=0 +IndexingJobAdminConverter 테스트 tests=4 fail=0 err=0 skipped=0 +FailDocumentIndexingRequest 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingJob 테스트 tests=11 fail=0 err=0 skipped=0 +EmbeddingModel 생성 검증 테스트 tests=4 fail=0 err=0 skipped=0 +Embedding 테스트 tests=3 fail=0 err=0 skipped=0 +IndexingFailureType 테스트 tests=12 fail=0 err=0 skipped=0 +Document Embedding OpenSQL 통합 테스트 tests=3 fail=0 err=0 skipped=0 +Document 인덱싱 완료 OpenSQL 통합 테스트 tests=4 fail=0 err=0 skipped=0 +Document 인덱싱 실패 PostgreSQL 통합 테스트 tests=6 fail=0 err=0 skipped=0 +Embedding Job Attempt OpenSQL 통합 테스트 tests=6 fail=0 err=0 skipped=0 +Embedding Job Claim DB 동시성 통합 테스트 tests=6 fail=0 err=0 skipped=0 +Embedding Job 수동 재처리 PostgreSQL 통합 테스트 tests=8 fail=0 err=0 skipped=0 +기본 임베딩 모델 DB 제약 통합 테스트 tests=9 fail=0 err=0 skipped=0 +관리자 인덱싱 조회 PostgreSQL 통합 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJob 대시보드 집계 Repository 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingModelRepository 테스트 tests=5 fail=0 err=0 skipped=0 +인덱싱 완료 Repository 테스트 tests=3 fail=0 err=0 skipped=0 +AdaptiveEmbeddingBatchPlanner 테스트 tests=5 fail=0 err=0 skipped=0 +DocumentEmbeddingGenerator 테스트 tests=8 fail=0 err=0 skipped=0 +DocumentEmbeddingService 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentEmbeddingTransactionService 테스트 tests=14 fail=0 err=0 skipped=0 +DocumentIndexingCompletionService 테스트 tests=9 fail=0 err=0 skipped=0 +DocumentIndexingFailureService 테스트 tests=11 fail=0 err=0 skipped=0 +EmbeddingJobAttemptService 테스트 tests=17 fail=0 err=0 skipped=0 +EmbeddingJobClaimService 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJobLeaseRecoveryService 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJobLeaseService 테스트 tests=4 fail=0 err=0 skipped=0 +EmbeddingJobManualRetryPolicy 테스트 tests=5 fail=0 err=0 skipped=0 +EmbeddingJobManualRetryService 테스트 tests=13 fail=0 err=0 skipped=0 +EmbeddingJobOwnershipValidator 테스트 tests=13 fail=0 err=0 skipped=0 +IndexedVersionVectorRepairService 단위 테스트 tests=1 fail=0 err=0 skipped=0 +IndexingRetryDelayPolicy 테스트 tests=5 fail=0 err=0 skipped=0 +EmbeddingJobRecoveryQueryService 테스트 tests=2 fail=0 err=0 skipped=0 +EmbeddingModelQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +IndexingJobAdminQueryService 테스트 tests=7 fail=0 err=0 skipped=0 +QueryEmbeddingService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +HaProbeWriteControllerTest tests=2 fail=0 err=0 skipped=0 +HaProbeWriteDisabledTest tests=1 fail=0 err=0 skipped=0 +HaProbeWriteFlagDisabledTest tests=1 fail=0 err=0 skipped=0 +HaProbeWriteSecurityTest tests=1 fail=0 err=0 skipped=0 +HaProbeWriteServiceTest tests=1 fail=0 err=0 skipped=0 +McpApiKeyAuthFilter 단위 테스트 tests=5 fail=0 err=0 skipped=0 +McpRateLimiter 단위 테스트 tests=7 fail=0 err=0 skipped=0 +McpAccessTokenCommandService 단위 테스트 tests=7 fail=0 err=0 skipped=0 +McpAccessTokenQueryService 단위 테스트 tests=1 fail=0 err=0 skipped=0 +DocGridMcpTools 단위 테스트 tests=20 fail=0 err=0 skipped=0 +PermissionController 테스트 tests=5 fail=0 err=0 skipped=0 +CollectionPermissionCommandService 단위 테스트 tests=11 fail=0 err=0 skipped=0 +DocumentPermissionCommandService 단위 테스트 tests=11 fail=0 err=0 skipped=0 +PermissionQueryService 단위 테스트 tests=54 fail=0 err=0 skipped=0 +PermissionTargetUserQueryService 테스트 tests=2 fail=0 err=0 skipped=0 +RagJobWorkerConcurrentQueueIntegrationTest tests=1 fail=0 err=0 skipped=0 +RagJobWorkerIntegrationTest tests=1 fail=0 err=0 skipped=0 +RagResponse Claim DB 동시성 통합 테스트 tests=2 fail=0 err=0 skipped=0 +RagResponseRepository 테스트 tests=9 fail=0 err=0 skipped=0 +OllamaClient 단위 테스트 tests=15 fail=0 err=0 skipped=0 +PromptBuilder 단위 테스트 tests=6 fail=0 err=0 skipped=0 +RagFacade 단위 테스트 tests=20 fail=0 err=0 skipped=0 +RagJobTimeoutSweeper 단위 테스트 tests=4 fail=0 err=0 skipped=0 +RagJobWorker 단위 테스트 tests=10 fail=0 err=0 skipped=0 +RagResponseCommandService 단위 테스트 tests=6 fail=0 err=0 skipped=0 +ResponseCitationCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +Vector 검색 성능 Benchmark 계약 테스트 tests=5 fail=0 err=0 skipped=0 +VectorSearchProperties 검증 테스트 tests=8 fail=0 err=0 skipped=0 +SearchController 테스트 tests=2 fail=0 err=0 skipped=0 +검색 실패 원장 트랜잭션 경계 통합 테스트 tests=4 fail=0 err=0 skipped=0 +SearchResultRepository 후보 DTO fetch 테스트 tests=2 fail=0 err=0 skipped=0 +SearchFacade 단위 테스트 tests=4 fail=0 err=0 skipped=0 +SearchConversationCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SearchQueryCommandService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +SearchResultCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +AccessibleDocumentQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +대화 상세 SQL 개수 통합 테스트 tests=1 fail=0 err=0 skipped=0 +SearchConversationQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +VectorSearchQueryService 단위 테스트 tests=9 fail=0 err=0 skipped=0 +SyncAdminController 테스트 tests=4 fail=0 err=0 skipped=0 +SyncEventDeliveryAttempt 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncOutboxEvent 상태 전이 테스트 tests=3 fail=0 err=0 skipped=0 +Embedding 저장 장애·Lease·Reconciler 복구 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Sync 관리자 감사 Action 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Sync Dispatch 장애 주입·복구 통합 테스트 tests=5 fail=0 err=0 skipped=0 +Sync Event Claim 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Sync Dispatcher 멱등성·동시성 통합 테스트 tests=3 fail=0 err=0 skipped=0 +Sync Outbox 트랜잭션 경계 통합 테스트 tests=5 fail=0 err=0 skipped=0 +SyncConsistencyInspector 단위 테스트 tests=3 fail=0 err=0 skipped=0 +SyncAdminCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventClaimService 단위 테스트 tests=1 fail=0 err=0 skipped=0 +SyncEventDispatchService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventFailureService 메트릭 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventLeaseRecoveryService 메트릭 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventWriter 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncReconciliationBatchService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +DocumentVersionSyncEventHandler 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncAdminQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +AdminUserController 테스트 tests=12 fail=0 err=0 skipped=0 +UserRepository 테스트 tests=2 fail=0 err=0 skipped=0 +UserCommandService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +UserRoleCommandService 단위 테스트 tests=5 fail=0 err=0 skipped=0 +AdminUserQueryService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +IndexingWorkerProperties 테스트 tests=10 fail=0 err=0 skipped=0 +WorkerAdminController 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingJobAttempt 테스트 tests=5 fail=0 err=0 skipped=0 +WorkerNode 상태 판정 테스트 tests=9 fail=0 err=0 skipped=0 +WorkerExecutionSlotPool 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerExecutionLifecycleManager 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerHeartbeatScheduler 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerJobPollingScheduler 테스트 tests=7 fail=0 err=0 skipped=0 +WorkerLeaseRecoveryScheduler 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerLifecycleManager 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerPollingBackoff 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerNodeRepository 테스트 tests=7 fail=0 err=0 skipped=0 +WorkerIndexingFailureClassifier 테스트 tests=5 fail=0 err=0 skipped=0 +WorkerIndexingFailureReporter 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerIndexingPipeline 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerLeaseRenewalManager 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerNodeCommandService 테스트 tests=6 fail=0 err=0 skipped=0 +WorkerNodeQueryService 테스트 tests=2 fail=0 err=0 skipped=0 +PDF DOCX 전체 인덱싱 부하 통계 단위 테스트 tests=2 fail=0 err=0 skipped=0 +Worker 수평 확장 통계 tests=3 fail=0 err=0 skipped=0 +Worker 인덱싱 처리량 통계 단위 테스트 tests=3 fail=0 err=0 skipped=0 +Worker Queue Backpressure 통계 tests=7 fail=0 err=0 skipped=0 +Management 엔드포인트 통합 테스트 tests=4 fail=0 err=0 skipped=0 +S3Config 테스트 tests=2 fail=0 err=0 skipped=0 +GlobalExceptionHandlerDataAccessTest tests=1 fail=0 err=0 skipped=0 +Security 예외 응답 단위 테스트 tests=2 fail=0 err=0 skipped=0 +비동기 파이프라인 Counter AFTER_COMMIT 통합 테스트 tests=2 fail=0 err=0 skipped=0 +비동기 파이프라인 상태 전이 Counter 테스트 tests=3 fail=0 err=0 skipped=0 +운영 상태 Snapshot Query 테스트 tests=2 fail=0 err=0 skipped=0 +운영 상태 Snapshot Refresher 테스트 tests=2 fail=0 err=0 skipped=0 +운영 상태 Gauge 테스트 tests=3 fail=0 err=0 skipped=0 +8 호환성·Vector 성능 통합 테스트 tests=3 fail=0 err=0 skipped=0 +합계 tests=1297 failures=0 errors=0 skipped=0 diff --git a/docs/test-results/evidence/issue-399/full-valkey-9.1.2-summary.txt b/docs/test-results/evidence/issue-399/full-valkey-9.1.2-summary.txt new file mode 100644 index 00000000..da64987a --- /dev/null +++ b/docs/test-results/evidence/issue-399/full-valkey-9.1.2-summary.txt @@ -0,0 +1,221 @@ +DocgridApplicationTests tests=1 fail=0 err=0 skipped=0 +SignupRequest 테스트 tests=3 fail=0 err=0 skipped=0 +로그아웃 PostgreSQL·Redis 통합 테스트 tests=1 fail=0 err=0 skipped=0 +STOMP 연결 인증 통합 테스트 tests=4 fail=0 err=0 skipped=0 +STOMP 실제 역할 회수 통합 테스트 tests=4 fail=0 err=0 skipped=0 +STOMP 관리자 권한 회수 경계 통합 테스트 tests=3 fail=0 err=0 skipped=0 +STOMP 목적지 인가 통합 테스트 tests=5 fail=0 err=0 skipped=0 +STOMP 세션 수명주기 통합 테스트 tests=4 fail=0 err=0 skipped=0 +JwtAuthenticationFilter 단위 테스트 tests=5 fail=0 err=0 skipped=0 +JwtProviderTest tests=1 fail=0 err=0 skipped=0 +RoleAuthorityService 단위 테스트 tests=6 fail=0 err=0 skipped=0 +StompAuthChannelInterceptor 단위 테스트 tests=11 fail=0 err=0 skipped=0 +TokenBlacklistService 단위 테스트 tests=5 fail=0 err=0 skipped=0 +AuthCommandService 단위 테스트 tests=14 fail=0 err=0 skipped=0 +AuthQueryService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +PrimaryRoleQueryService 단위 테스트 tests=7 fail=0 err=0 skipped=0 +STOMP 대시보드 outbound 인가 단위 테스트 tests=7 fail=0 err=0 skipped=0 +STOMP 목적지 인가 Interceptor 단위 테스트 tests=22 fail=0 err=0 skipped=0 +STOMP 세션 Registry 단위 테스트 tests=5 fail=0 err=0 skipped=0 +STOMP 세션 재검증 Scheduler 단위 테스트 tests=7 fail=0 err=0 skipped=0 +CollectionController 테스트 tests=5 fail=0 err=0 skipped=0 +컬렉션 트리 Repository 테스트 tests=16 fail=0 err=0 skipped=0 +CollectionCommandService 단위 테스트 tests=25 fail=0 err=0 skipped=0 +CollectionQueryService 단위 테스트 tests=14 fail=0 err=0 skipped=0 +대시보드 WebSocket 발행 권한 일괄 조회 단위 테스트 tests=4 fail=0 err=0 skipped=0 +대시보드 교차 백엔드 Redis Pub/Sub 통합 테스트 tests=1 fail=0 err=0 skipped=0 +대시보드 교차 백엔드 갱신 신호 단위 테스트 tests=4 fail=0 err=0 skipped=0 +대시보드 A/B Spring 앱·WebSocket 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Dashboard push debounce burst 통합 테스트 tests=1 fail=0 err=0 skipped=0 +DashboardPushScheduler 단위 테스트 tests=7 fail=0 err=0 skipped=0 +DashboardUpdateFlag 단위 테스트 tests=4 fail=0 err=0 skipped=0 +Embedding Job 상태 전이 이벤트 AFTER_COMMIT 통합 테스트 tests=2 fail=0 err=0 skipped=0 +EmbeddingJobStatusChangedEventListener 단위 테스트 tests=1 fail=0 err=0 skipped=0 +EmbeddingJobRetryService 단위 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJobRetryService 트랜잭션 독립성 통합 테스트 tests=1 fail=0 err=0 skipped=0 +대시보드 집계 SQL 개수 통합 테스트 tests=1 fail=0 err=0 skipped=0 +DashboardQueryService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +Dashboard WebSocket 실시간 push 통합 테스트 tests=4 fail=0 err=0 skipped=0 +Chunk Size·Overlap 품질 Benchmark 계약 테스트 tests=9 fail=0 err=0 skipped=0 +DocumentChunkingProperties 테스트 tests=3 fail=0 err=0 skipped=0 +문서 업로드 제한 설정 테스트 tests=1 fail=0 err=0 skipped=0 +FileStorageProperties 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentCommandController 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentQueryController 테스트 tests=10 fail=0 err=0 skipped=0 +DocumentUploadController 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentDetailConverter 테스트 tests=1 fail=0 err=0 skipped=0 +DocumentStatusConverter 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentVersionHistoryConverter 단위 테스트 tests=1 fail=0 err=0 skipped=0 +Document 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentVersion 테스트 tests=29 fail=0 err=0 skipped=0 +Document Chunking OpenSQL 통합 테스트 tests=5 fail=0 err=0 skipped=0 +문서 업로드 통합 테스트 tests=4 fail=0 err=0 skipped=0 +문서 새 버전 업로드 통합 테스트 tests=4 fail=0 err=0 skipped=0 +S3 저장소 Spring Context 통합 테스트 tests=1 fail=0 err=0 skipped=0 +읽기 가능 문서 ID Repository 테스트 tests=7 fail=0 err=0 skipped=0 +findByIdWithCurrentVersion 테스트 tests=2 fail=0 err=0 skipped=0 +문서 상태 Projection Repository 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentFileService 테스트 tests=2 fail=0 err=0 skipped=0 +DocumentParserRegistry 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentParsingService 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentUploadFacade 단위 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentVersionUploadFacade 단위 테스트 tests=6 fail=0 err=0 skipped=0 +DocxDocumentParser 테스트 tests=3 fail=0 err=0 skipped=0 +FileHashService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +FileValidationService 단위 테스트 tests=12 fail=0 err=0 skipped=0 +FixedSizeChunker 테스트 tests=10 fail=0 err=0 skipped=0 +PdfDocumentParser 테스트 tests=10 fail=0 err=0 skipped=0 +TextDocumentParser 테스트 tests=6 fail=0 err=0 skipped=0 +DocumentChunkTransactionService 테스트 tests=10 fail=0 err=0 skipped=0 +DocumentCommandService 단위 테스트 tests=8 fail=0 err=0 skipped=0 +DocumentUploadService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentVersionUploadService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +FileObjectResolutionService 테스트 tests=4 fail=0 err=0 skipped=0 +DocumentQueryService 테스트 tests=19 fail=0 err=0 skipped=0 +GcsStorageService 테스트 tests=7 fail=0 err=0 skipped=0 +LocalFileStorageService 테스트 tests=6 fail=0 err=0 skipped=0 +MinioStorageService 테스트 tests=6 fail=0 err=0 skipped=0 +S3StorageService 테스트 tests=8 fail=0 err=0 skipped=0 +실제 PDF Embedding Corpus Exporter 테스트 tests=1 fail=0 err=0 skipped=0 +Vector 저장 Benchmark 지원 계약 tests=6 fail=0 err=0 skipped=0 +EmbeddingClient 단위 테스트 tests=19 fail=0 err=0 skipped=0 +EmbeddingProviderCircuitBreaker 테스트 tests=7 fail=0 err=0 skipped=0 +EmbeddingBatchProperties 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingProviderCircuitBreakerProperties 테스트 tests=2 fail=0 err=0 skipped=0 +EmbeddingModelController 테스트 tests=3 fail=0 err=0 skipped=0 +IndexingJobAdminController 테스트 tests=104 fail=0 err=0 skipped=0 +IndexingJobAdminController 조회 테스트 tests=17 fail=0 err=0 skipped=0 +EmbeddingJobAttemptConverter 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingJobConverter 테스트 tests=1 fail=0 err=0 skipped=0 +IndexingJobAdminConverter 테스트 tests=4 fail=0 err=0 skipped=0 +FailDocumentIndexingRequest 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingJob 테스트 tests=11 fail=0 err=0 skipped=0 +EmbeddingModel 생성 검증 테스트 tests=4 fail=0 err=0 skipped=0 +Embedding 테스트 tests=3 fail=0 err=0 skipped=0 +IndexingFailureType 테스트 tests=12 fail=0 err=0 skipped=0 +Document Embedding OpenSQL 통합 테스트 tests=3 fail=0 err=0 skipped=0 +Document 인덱싱 완료 OpenSQL 통합 테스트 tests=4 fail=0 err=0 skipped=0 +Document 인덱싱 실패 PostgreSQL 통합 테스트 tests=6 fail=0 err=0 skipped=0 +Embedding Job Attempt OpenSQL 통합 테스트 tests=6 fail=0 err=0 skipped=0 +Embedding Job Claim DB 동시성 통합 테스트 tests=6 fail=0 err=0 skipped=0 +Embedding Job 수동 재처리 PostgreSQL 통합 테스트 tests=8 fail=0 err=0 skipped=0 +기본 임베딩 모델 DB 제약 통합 테스트 tests=9 fail=0 err=0 skipped=0 +관리자 인덱싱 조회 PostgreSQL 통합 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJob 대시보드 집계 Repository 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingModelRepository 테스트 tests=5 fail=0 err=0 skipped=0 +인덱싱 완료 Repository 테스트 tests=3 fail=0 err=0 skipped=0 +AdaptiveEmbeddingBatchPlanner 테스트 tests=5 fail=0 err=0 skipped=0 +DocumentEmbeddingGenerator 테스트 tests=8 fail=0 err=0 skipped=0 +DocumentEmbeddingService 테스트 tests=3 fail=0 err=0 skipped=0 +DocumentEmbeddingTransactionService 테스트 tests=14 fail=0 err=0 skipped=0 +DocumentIndexingCompletionService 테스트 tests=9 fail=0 err=0 skipped=0 +DocumentIndexingFailureService 테스트 tests=11 fail=0 err=0 skipped=0 +EmbeddingJobAttemptService 테스트 tests=17 fail=0 err=0 skipped=0 +EmbeddingJobClaimService 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJobLeaseRecoveryService 테스트 tests=6 fail=0 err=0 skipped=0 +EmbeddingJobLeaseService 테스트 tests=4 fail=0 err=0 skipped=0 +EmbeddingJobManualRetryPolicy 테스트 tests=5 fail=0 err=0 skipped=0 +EmbeddingJobManualRetryService 테스트 tests=13 fail=0 err=0 skipped=0 +EmbeddingJobOwnershipValidator 테스트 tests=13 fail=0 err=0 skipped=0 +IndexedVersionVectorRepairService 단위 테스트 tests=1 fail=0 err=0 skipped=0 +IndexingRetryDelayPolicy 테스트 tests=5 fail=0 err=0 skipped=0 +EmbeddingJobRecoveryQueryService 테스트 tests=2 fail=0 err=0 skipped=0 +EmbeddingModelQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +IndexingJobAdminQueryService 테스트 tests=7 fail=0 err=0 skipped=0 +QueryEmbeddingService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +HaProbeWriteControllerTest tests=2 fail=0 err=0 skipped=0 +HaProbeWriteDisabledTest tests=1 fail=0 err=0 skipped=0 +HaProbeWriteFlagDisabledTest tests=1 fail=0 err=0 skipped=0 +HaProbeWriteSecurityTest tests=1 fail=0 err=0 skipped=0 +HaProbeWriteServiceTest tests=1 fail=0 err=0 skipped=0 +McpApiKeyAuthFilter 단위 테스트 tests=5 fail=0 err=0 skipped=0 +McpRateLimiter 단위 테스트 tests=7 fail=0 err=0 skipped=0 +McpAccessTokenCommandService 단위 테스트 tests=7 fail=0 err=0 skipped=0 +McpAccessTokenQueryService 단위 테스트 tests=1 fail=0 err=0 skipped=0 +DocGridMcpTools 단위 테스트 tests=20 fail=0 err=0 skipped=0 +PermissionController 테스트 tests=5 fail=0 err=0 skipped=0 +CollectionPermissionCommandService 단위 테스트 tests=11 fail=0 err=0 skipped=0 +DocumentPermissionCommandService 단위 테스트 tests=11 fail=0 err=0 skipped=0 +PermissionQueryService 단위 테스트 tests=54 fail=0 err=0 skipped=0 +PermissionTargetUserQueryService 테스트 tests=2 fail=0 err=0 skipped=0 +RagJobWorkerConcurrentQueueIntegrationTest tests=1 fail=0 err=0 skipped=0 +RagJobWorkerIntegrationTest tests=1 fail=0 err=0 skipped=0 +RagResponse Claim DB 동시성 통합 테스트 tests=2 fail=0 err=0 skipped=0 +RagResponseRepository 테스트 tests=9 fail=0 err=0 skipped=0 +OllamaClient 단위 테스트 tests=15 fail=0 err=0 skipped=0 +PromptBuilder 단위 테스트 tests=6 fail=0 err=0 skipped=0 +RagFacade 단위 테스트 tests=20 fail=0 err=0 skipped=0 +RagJobTimeoutSweeper 단위 테스트 tests=4 fail=0 err=0 skipped=0 +RagJobWorker 단위 테스트 tests=10 fail=0 err=0 skipped=0 +RagResponseCommandService 단위 테스트 tests=6 fail=0 err=0 skipped=0 +ResponseCitationCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +Vector 검색 성능 Benchmark 계약 테스트 tests=5 fail=0 err=0 skipped=0 +VectorSearchProperties 검증 테스트 tests=8 fail=0 err=0 skipped=0 +SearchController 테스트 tests=2 fail=0 err=0 skipped=0 +검색 실패 원장 트랜잭션 경계 통합 테스트 tests=4 fail=0 err=0 skipped=0 +SearchResultRepository 후보 DTO fetch 테스트 tests=2 fail=0 err=0 skipped=0 +SearchFacade 단위 테스트 tests=4 fail=0 err=0 skipped=0 +SearchConversationCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SearchQueryCommandService 단위 테스트 tests=3 fail=0 err=0 skipped=0 +SearchResultCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +AccessibleDocumentQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +대화 상세 SQL 개수 통합 테스트 tests=1 fail=0 err=0 skipped=0 +SearchConversationQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +VectorSearchQueryService 단위 테스트 tests=9 fail=0 err=0 skipped=0 +SyncAdminController 테스트 tests=4 fail=0 err=0 skipped=0 +SyncEventDeliveryAttempt 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncOutboxEvent 상태 전이 테스트 tests=3 fail=0 err=0 skipped=0 +Embedding 저장 장애·Lease·Reconciler 복구 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Sync 관리자 감사 Action 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Sync Dispatch 장애 주입·복구 통합 테스트 tests=5 fail=0 err=0 skipped=0 +Sync Event Claim 통합 테스트 tests=1 fail=0 err=0 skipped=0 +Sync Dispatcher 멱등성·동시성 통합 테스트 tests=3 fail=0 err=0 skipped=0 +Sync Outbox 트랜잭션 경계 통합 테스트 tests=5 fail=0 err=0 skipped=0 +SyncConsistencyInspector 단위 테스트 tests=3 fail=0 err=0 skipped=0 +SyncAdminCommandService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventClaimService 단위 테스트 tests=1 fail=0 err=0 skipped=0 +SyncEventDispatchService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventFailureService 메트릭 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventLeaseRecoveryService 메트릭 테스트 tests=2 fail=0 err=0 skipped=0 +SyncEventWriter 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncReconciliationBatchService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +DocumentVersionSyncEventHandler 단위 테스트 tests=2 fail=0 err=0 skipped=0 +SyncAdminQueryService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +AdminUserController 테스트 tests=12 fail=0 err=0 skipped=0 +UserRepository 테스트 tests=2 fail=0 err=0 skipped=0 +UserCommandService 단위 테스트 tests=4 fail=0 err=0 skipped=0 +UserRoleCommandService 단위 테스트 tests=5 fail=0 err=0 skipped=0 +AdminUserQueryService 단위 테스트 tests=2 fail=0 err=0 skipped=0 +IndexingWorkerProperties 테스트 tests=10 fail=0 err=0 skipped=0 +WorkerAdminController 테스트 tests=3 fail=0 err=0 skipped=0 +EmbeddingJobAttempt 테스트 tests=5 fail=0 err=0 skipped=0 +WorkerNode 상태 판정 테스트 tests=9 fail=0 err=0 skipped=0 +WorkerExecutionSlotPool 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerExecutionLifecycleManager 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerHeartbeatScheduler 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerJobPollingScheduler 테스트 tests=7 fail=0 err=0 skipped=0 +WorkerLeaseRecoveryScheduler 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerLifecycleManager 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerPollingBackoff 테스트 tests=2 fail=0 err=0 skipped=0 +WorkerNodeRepository 테스트 tests=7 fail=0 err=0 skipped=0 +WorkerIndexingFailureClassifier 테스트 tests=5 fail=0 err=0 skipped=0 +WorkerIndexingFailureReporter 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerIndexingPipeline 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerLeaseRenewalManager 테스트 tests=4 fail=0 err=0 skipped=0 +WorkerNodeCommandService 테스트 tests=6 fail=0 err=0 skipped=0 +WorkerNodeQueryService 테스트 tests=2 fail=0 err=0 skipped=0 +PDF DOCX 전체 인덱싱 부하 통계 단위 테스트 tests=2 fail=0 err=0 skipped=0 +Worker 수평 확장 통계 tests=3 fail=0 err=0 skipped=0 +Worker 인덱싱 처리량 통계 단위 테스트 tests=3 fail=0 err=0 skipped=0 +Worker Queue Backpressure 통계 tests=7 fail=0 err=0 skipped=0 +Management 엔드포인트 통합 테스트 tests=4 fail=0 err=0 skipped=0 +S3Config 테스트 tests=2 fail=0 err=0 skipped=0 +GlobalExceptionHandlerDataAccessTest tests=1 fail=0 err=0 skipped=0 +Security 예외 응답 단위 테스트 tests=2 fail=0 err=0 skipped=0 +비동기 파이프라인 Counter AFTER_COMMIT 통합 테스트 tests=2 fail=0 err=0 skipped=0 +비동기 파이프라인 상태 전이 Counter 테스트 tests=3 fail=0 err=0 skipped=0 +운영 상태 Snapshot Query 테스트 tests=2 fail=0 err=0 skipped=0 +운영 상태 Snapshot Refresher 테스트 tests=2 fail=0 err=0 skipped=0 +운영 상태 Gauge 테스트 tests=3 fail=0 err=0 skipped=0 +8 호환성·Vector 성능 통합 테스트 tests=3 fail=0 err=0 skipped=0 +합계 tests=1297 failures=0 errors=0 skipped=0 diff --git a/docs/test-results/evidence/issue-399/summarize.py b/docs/test-results/evidence/issue-399/summarize.py new file mode 100644 index 00000000..ee93b11c --- /dev/null +++ b/docs/test-results/evidence/issue-399/summarize.py @@ -0,0 +1,15 @@ +import glob +import sys +import xml.etree.ElementTree as ET + +directory = sys.argv[1] if len(sys.argv) > 1 else "/Users/kangcheolung/cotato/docgrid/backend/build/test-results/test" +totals = [0, 0, 0, 0] +rows = [] +for path in sorted(glob.glob(directory + "/*.xml")): + root = ET.parse(path).getroot() + counts = [int(root.get(key, 0)) for key in ("tests", "failures", "errors", "skipped")] + totals = [a + b for a, b in zip(totals, counts)] + rows.append((root.get("name").split(".")[-1], counts)) +for name, c in rows: + print(f"{name:70s} tests={c[0]:<4} fail={c[1]:<3} err={c[2]:<3} skipped={c[3]}") +print("합계 tests=%d failures=%d errors=%d skipped=%d" % tuple(totals)) diff --git a/docs/test-results/evidence/issue-399/verify-e2e.log b/docs/test-results/evidence/issue-399/verify-e2e.log new file mode 100644 index 00000000..5787bbac --- /dev/null +++ b/docs/test-results/evidence/issue-399/verify-e2e.log @@ -0,0 +1,205 @@ +Unable to find image 'prom/prometheus:v3.5.5' locally +v3.5.5: Pulling from prom/prometheus +a03b0fa940b1: Pulling fs layer +7a21057f59f5: Pulling fs layer +905e8aa01b13: Pulling fs layer +aa2b3c16fb92: Pulling fs layer +788b085682b4: Pulling fs layer +66d02544ade1: Pulling fs layer +55493eaebe55: Pulling fs layer +b718c71eb0d8: Pulling fs layer +d7a574078986: Pulling fs layer +3d49b2164575: Pulling fs layer +a03b0fa940b1: Download complete +905e8aa01b13: Download complete +3d49b2164575: Download complete +aa2b3c16fb92: Download complete +55493eaebe55: Download complete +7a21057f59f5: Download complete +788b085682b4: Download complete +d7a574078986: Download complete +905e8aa01b13: Pull complete +7a21057f59f5: Pull complete +66d02544ade1: Download complete +66d02544ade1: Pull complete +b718c71eb0d8: Download complete +a03b0fa940b1: Pull complete +3d49b2164575: Pull complete +aa2b3c16fb92: Pull complete +55493eaebe55: Pull complete +788b085682b4: Pull complete +d7a574078986: Pull complete +b718c71eb0d8: Pull complete +Digest: sha256:332c2f43e7e389d74d3893b55bb02fbbd684208e681eeb604641d5d769c0fe2a +Status: Downloaded newer image for prom/prometheus:v3.5.5 +Checking /etc/prometheus/prometheus.yml + SUCCESS: 3 rule files found + SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax + +Checking /etc/prometheus/rules/docgrid-backend-alerts.yml + SUCCESS: 3 rules found + +Checking /etc/prometheus/rules/docgrid-pipeline-alerts.yml + SUCCESS: 9 rules found + +Checking /etc/prometheus/rules/embedding-provider-alerts.yml + SUCCESS: 7 rules found + +Checking /etc/prometheus/rules/embedding-provider-alerts.yml + SUCCESS: 7 rules found + +Checking /etc/prometheus/rules/docgrid-backend-alerts.yml + SUCCESS: 3 rules found + +Checking /etc/prometheus/rules/docgrid-pipeline-alerts.yml + SUCCESS: 9 rules found + + SUCCESS + + SUCCESS + + SUCCESS + +Checking /test/rules-firing.yml + SUCCESS: 3 rules found + +Checking /test/rules-resolved.yml + SUCCESS: 3 rules found + +Unable to find image 'quay.io/prometheus/alertmanager:v0.33.1' locally +v0.33.1: Pulling from prometheus/alertmanager +4f4fb700ef54: Pulling fs layer +bc568a425d6c: Pulling fs layer +b206c4e2f56d: Pulling fs layer +91b78d9e43f9: Pulling fs layer +b90af14651b3: Pulling fs layer +4f4fb700ef54: Already exists +b90af14651b3: Download complete +91b78d9e43f9: Download complete +bc568a425d6c: Download complete +bc568a425d6c: Pull complete +b206c4e2f56d: Download complete +4f4fb700ef54: Pull complete +b90af14651b3: Pull complete +91b78d9e43f9: Pull complete +b206c4e2f56d: Pull complete +Digest: sha256:9e082985f56f4c8c9f724e18f2288c6708f472e56a5286b8863d080434ea065d +Status: Downloaded newer image for quay.io/prometheus/alertmanager:v0.33.1 +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 1 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + +Checking '/etc/alertmanager/alertmanager.yml' SUCCESS +Found: + - global config + - route + - 2 inhibit rules + - 1 receivers + - 0 templates + + webhook-receiver Pulling + 6db16a24faac Pulling fs layer + 4617d3b35936 Pulling fs layer + 02bd2e91174a Pulling fs layer + 02bd2e91174a Downloading [==================================================>] 419.1kB/419.1kB + 02bd2e91174a Download complete + 02bd2e91174a Pull complete + 6db16a24faac Download complete + 4617d3b35936 Downloading [======> ] 2.097MB/15.65MB + 4617d3b35936 Downloading [==========================> ] 8.389MB/15.65MB + 4617d3b35936 Downloading [===========================================> ] 13.63MB/15.65MB + 4617d3b35936 Download complete + 4617d3b35936 Extracting 1 s + 4617d3b35936 Extracting 1 s + 4617d3b35936 Extracting 1 s + 4617d3b35936 Extracting 1 s + 6db16a24faac Pull complete + 4617d3b35936 Pull complete + webhook-receiver Pulled + Network docgrid-alertmanager-e2e-431_default Creating + Network docgrid-alertmanager-e2e-431_default Created + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Creating + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Created + Container docgrid-alertmanager-e2e-431-alertmanager-1 Creating + Container docgrid-alertmanager-e2e-431-alertmanager-1 Created + Container docgrid-alertmanager-e2e-431-prometheus-1 Creating + Container docgrid-alertmanager-e2e-431-prometheus-1 Created + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Starting + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Started + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Waiting + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Healthy + Container docgrid-alertmanager-e2e-431-alertmanager-1 Starting + Container docgrid-alertmanager-e2e-431-alertmanager-1 Started + Container docgrid-alertmanager-e2e-431-alertmanager-1 Waiting + Container docgrid-alertmanager-e2e-431-alertmanager-1 Healthy + Container docgrid-alertmanager-e2e-431-prometheus-1 Starting + Container docgrid-alertmanager-e2e-431-prometheus-1 Started + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Waiting + Container docgrid-alertmanager-e2e-431-alertmanager-1 Waiting + Container docgrid-alertmanager-e2e-431-prometheus-1 Waiting + Container docgrid-alertmanager-e2e-431-alertmanager-1 Healthy + Container docgrid-alertmanager-e2e-431-webhook-receiver-1 Healthy + Container docgrid-alertmanager-e2e-431-prometheus-1 Healthy +Alertmanager routing E2E: SUCCESS (firing 2s, resolved 2s) +Monitoring configuration validation: SUCCESS +verify exit=0 From f1bde65c0b7405edbf120b3158a1fc16fb89317c Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Sat, 3 Oct 2026 18:24:35 +0900 Subject: [PATCH 3/3] =?UTF-8?q?docs:=20CodeRabbit=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=20-=20=EC=A0=84=ED=99=98=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=C2=B7=EB=A1=A4=EB=B0=B1=20=EC=84=A4=EB=AA=85=20?= =?UTF-8?q?=EC=A0=95=EC=A0=95=EA=B3=BC=20=EC=B0=A8=EB=8B=A8=20=ED=82=A4=20?= =?UTF-8?q?=EC=A3=BC=EC=9D=98=EC=82=AC=ED=95=AD=20=EC=B6=94=EA=B0=80=20(#3?= =?UTF-8?q?99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로컬 전환 절차를 기존 docgrid-redis 컨테이너 제거 후 valkey 시작 순서로 수정 (기존 컨테이너가 6379를 점유하면 valkey가 뜨지 못함) - 롤백 설명의 "블랙리스트는 DB에서 다시 채워진다"는 오류를 정정: 역할 캐시만 DB에서 복구되고 로그아웃 차단 키(auth:blacklist:*)는 복구되지 않음 - 서버 교체·롤백 시 로그아웃 차단 키 유실 영향과 공용·운영 성격 환경의 대응 3가지 추가 - 로그아웃 차단 키 등록·조회를 실제 PostgreSQL·Valkey로 검증한 AuthLogoutIntegrationTest 결과를 검증 표에 명시 - summarize.py: 결과 디렉터리를 필수 인자로 받고 XML이 없으면 오류로 종료 Co-Authored-By: Claude Sonnet 5.5 --- .../kangcheolung-#399-valkey-migration.md | 41 +++++++++++++++++-- .../evidence/issue-399/summarize.py | 15 ++++++- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/docs/design/kangcheolung-#399-valkey-migration.md b/docs/design/kangcheolung-#399-valkey-migration.md index bcb27a7a..5169284e 100644 --- a/docs/design/kangcheolung-#399-valkey-migration.md +++ b/docs/design/kangcheolung-#399-valkey-migration.md @@ -214,6 +214,7 @@ Valkey는 Redis 7.2.4에서 갈라져 나온 포크로 같은 Redis 프로토콜 | drill compose의 `valkey` 단독 기동 | healthy, `docker compose port valkey 6379`로 동적 포트 조회 성공 (`run_drill.py`가 쓰는 방식) | | 이미지 확인 | Docker Hub에 `valkey/valkey:9.1-alpine` 태그 존재(마지막 갱신 2026-09-21), `valkey-server --version` = 9.1.2, 이미지에 `valkey-cli`와 호환용 `redis-cli`가 모두 포함(healthcheck·스크립트는 `valkey-cli` 사용) | | `INFO server` 응답 | `redis_version:7.2.4`(호환용), `valkey_version:9.1.2`, `server_name:valkey` | +| 로그아웃 차단 키 등록·조회 (실제 PostgreSQL·Valkey) | `AuthLogoutIntegrationTest`(`로그아웃 PostgreSQL·Redis 통합 테스트`) 통과. 로그인한 토큰은 로그아웃 전 `isBlacklisted=false`, `AuthCommandService.logout()` 뒤 `true`로 Valkey에 `auth:blacklist:`가 저장·조회된다. 전체 테스트 결과표에 포함되어 있다. 서비스 계층에서 확인한 것이며, 앱을 직접 띄워 HTTP로 호출하는 수동 확인은 하지 않았다 | | `docker compose config -q` (루트·drill) | 통과 | | `bash -n scripts/local-services.sh`, `py_compile run_drill.py` | 통과 | | `./monitoring/verify.sh --e2e` (CI와 동일) | 통과 (`Monitoring configuration validation: SUCCESS`, Alertmanager routing E2E 성공) | @@ -239,20 +240,49 @@ Valkey는 Redis 7.2.4에서 갈라져 나온 포크로 같은 Redis 프로토콜 | 8/27 제출 SBOM | Redis 항목의 표기·버전·라이선스가 실제(7.4.x, RSALv2/SSPLv1)와 다르게 적혀 있다면 정정본을 레포에 올린다 | SBOM 제출 담당 | | 운영규정 원문 | 평가 기준이 정말 OSI 승인인지, 이름에 Redis가 들어간 구성요소(클라이언트 라이브러리, 환경변수)가 문제가 되지 않는지 확인한다. 불확실하면 운영사무국에 문의한다 | 팀 | | 서비스명 변경 공지 | `docker compose up -d redis`를 쓰던 팀원은 `valkey`로 바꿔야 한다 | 팀 전체 | +| 공용·운영 성격 서버 교체·롤백 시 로그아웃 차단 키 | 서버나 볼륨을 바꾸면 `auth:blacklist:*` 키가 넘어가지 않는다. 아래 "서버 교체·롤백 시 로그아웃 차단 키" 참고 | 인프라 담당 팀원 | + +--- + +## 서버 교체·롤백 시 로그아웃 차단 키(`auth:blacklist:*`) + +서버나 볼륨을 바꾸면 이 키가 새 서버로 넘어가지 않는다는 점을 알고 진행해야 한다. + +- 로그아웃하면 `AuthCommandService.logout()`이 토큰의 `jti`를 `auth:blacklist:` 키로 저장한다. 키의 TTL은 토큰의 **남은 만료 시간**이다. +- 인증 필터는 이 키가 있으면 토큰을 거부하고, **없으면 허용**한다. 그래서 키가 사라지면 로그아웃한 토큰이 만료되기 전까지 HTTP·STOMP 인증을 다시 통과할 수 있다. +- 같은 서버 안의 역할 캐시는 키가 사라져도 DB에서 다시 채워지지만, **차단 키는 어디에서도 복구되지 않는다.** +- 영향 범위는 교체 시점 직전 `JWT_EXPIRATION`(기본 3600초) 안에 로그아웃한 토큰뿐이다. 그 시간이 지나면 토큰 자체가 만료되어 위험이 사라진다. +- 롤백도 대칭이다. Valkey를 쓰는 동안 생긴 차단 키는 Redis로 자동 이전되지 않는다. + +| 환경 | 영향 | 대응 | +|---|---|---| +| 로컬 개발 | 미미함. 개발 PC의 로그아웃 토큰은 보안 경계가 아니다 | 별도 조치 불필요 | +| GCP A/B 공용 서버 등 공용·운영 성격 환경 | 교체·롤백 직전 만료 시간 안에 로그아웃한 토큰이 다시 유효해질 수 있다 | 아래 셋 중 하나 | + +공용·운영 성격 환경의 대응 (하나를 선택): +1. 마지막 로그아웃으로부터 토큰 만료 시간(기본 1시간)이 지난 뒤에 교체·롤백한다. +2. 차단 키를 남은 TTL과 함께 새 서버로 옮긴다. 이전 중에 생기는 로그아웃은 놓치지 않도록 쓰기를 막은 상태에서 옮기고, 롤백 때는 교체 이후에 생긴 키도 되돌려야 한다. +3. JWT 서명 키(`JWT_SECRET`)를 교체해 기존 토큰을 모두 무효화한다. 모든 사용자가 다시 로그인해야 한다. --- ## 팀원 로컬 전환 방법 +기존 `docgrid-redis` 컨테이너가 6379 포트를 잡고 있으면 새 `valkey`가 뜨지 못하므로, **기존 컨테이너를 먼저 제거**한 뒤 시작한다. + ```bash -# 이전 redis 서비스를 대체합니다 +# 1) 기존 Redis 컨테이너 제거 (없으면 무시) +docker rm -f docgrid-redis + +# 2) Valkey 시작 (이전 redis 서비스를 대체합니다) docker compose up -d --wait valkey -# 선택: 더 이상 쓰지 않는 기존 컨테이너·볼륨 정리 (블랙리스트·역할 캐시만 있어 지워도 됩니다) -docker rm docgrid-redis +# 3) 선택: 더 이상 쓰지 않는 기존 볼륨 정리 (이름은 `docker volume ls | grep redis-data`로 확인) docker volume rm docgrid_redis-data ``` +볼륨을 지우면 그 안의 로그아웃 차단 키도 사라지지만, 로컬 개발 환경에서는 영향이 미미하다(위 표 참고). + 6379 포트를 Homebrew `redis-server`가 쓰고 있다면 먼저 `brew services stop redis`로 멈추거나 `REDIS_PORT`를 다른 값으로 지정합니다. --- @@ -284,4 +314,7 @@ docker exec docgrid-valkey valkey-cli INFO commandstats ## 롤백 -이미지 태그와 이름을 되돌리면 된다(`git revert`). Valkey 볼륨(`valkey-data`)과 기존 Redis 볼륨(`redis-data`)에는 로그아웃 토큰 블랙리스트와 역할 캐시만 있어 데이터 손실 영향이 없다. 두 값 모두 만료되거나 DB에서 다시 채워진다. +이미지 태그와 이름을 되돌리면 된다(`git revert`). 두 볼륨(`valkey-data`, `redis-data`)에는 로그아웃 차단 키와 역할 캐시뿐이다. + +- **역할 캐시**: 사라져도 DB에서 다시 채워지므로 영향이 없다. +- **로그아웃 차단 키**: Valkey 볼륨의 데이터는 기존 Redis 볼륨으로 자동 이전되지 않고, 복구 수단도 없다. 롤백하면 Valkey를 쓰는 동안 생긴 차단 키가 Redis에 없어, 롤백 직전 토큰 만료 시간(기본 3600초) 안에 로그아웃한 토큰이 다시 유효해질 수 있다. 로컬 개발 환경에서는 영향이 미미하고, 공용·운영 성격 환경에서는 위 "서버 교체·롤백 시 로그아웃 차단 키"의 대응을 따른다. diff --git a/docs/test-results/evidence/issue-399/summarize.py b/docs/test-results/evidence/issue-399/summarize.py index ee93b11c..856c74a9 100644 --- a/docs/test-results/evidence/issue-399/summarize.py +++ b/docs/test-results/evidence/issue-399/summarize.py @@ -1,11 +1,22 @@ +"""Gradle 테스트 결과 XML을 클래스별로 집계한다. + +사용법: python3 summarize.py +""" import glob import sys import xml.etree.ElementTree as ET -directory = sys.argv[1] if len(sys.argv) > 1 else "/Users/kangcheolung/cotato/docgrid/backend/build/test-results/test" +if len(sys.argv) != 2: + sys.exit("사용법: python3 summarize.py ") + +directory = sys.argv[1] +paths = sorted(glob.glob(directory + "/*.xml")) +if not paths: + sys.exit(f"테스트 결과 XML이 없습니다: {directory}") + totals = [0, 0, 0, 0] rows = [] -for path in sorted(glob.glob(directory + "/*.xml")): +for path in paths: root = ET.parse(path).getroot() counts = [int(root.get(key, 0)) for key in ("tests", "failures", "errors", "skipped")] totals = [a + b for a, b in zip(totals, counts)]