# Android target 통합테스트 진행 시나리오

작성일: 2026-07-03
상태: v0.1 진행 중

목적: `tdc114plus` Flutter 앱의 실제 Baron SSO API 로그인, 직원목록 진입, 플랫폼 액션 수동 검증을 Android 실기기 우선, emulator fallback 기준으로 단계적으로 확인한다.

## 1. 적용 범위

이 시나리오는 아래 작업에 적용한다.

- Android 실기기 준비
- Android emulator fallback 준비
- Android 런타임에서 Baron SSO local API 접근 확인
- `app/integration_test/` + `app/test_driver/` 기반 Flutter integration test 실행
- 실제 기기 수동 smoke: 로그인, 직원목록, 전화/문자 버튼, 즐겨찾기 유지

Playwright MCP는 이 시나리오의 실행 대상이 아니다. Playwright MCP가 필요한 단계가 오면 테스트 정책에 따라 사용자 확인과 정책 문서 갱신을 먼저 진행한다.

## 2. 사전 원칙

- 전화번호와 token은 명령 출력, 문서, git tracked 파일에 남기지 않는다.
- `scripts/.env.smoke.local`, `scripts/.env.android-emulator.local`, `scripts/.env.android-device.local`은 `.gitignore` 대상이다.
- 기본 테스트 타깃은 Android 실기기다.
- Android emulator에서는 host `127.0.0.1`이 아니라 보통 `10.0.2.2`로 host machine에 접근한다.
- Android 실기기는 `adb reverse` 또는 PC LAN IP 중 하나를 선택한다.
- Flutter 앱 변경 후에는 `./scripts/format-dart.sh`, `./scripts/quality-gate.sh`를 실행한다.
- 테스트 실행 결과는 `docs/test-logs/2026-07-test-execution-log.md`에 누적 기록한다.

## 3. 진행 체크리스트

| 단계 | 상태 | 목적 | 명령/확인 | 완료 기준 |
| --- | --- | --- | --- | --- |
| 0 | 완료 | 시나리오 문서 생성 | 본 문서 작성 | 문서가 `docs/`에 존재 |
| 1 | 완료 | Baron SSO local runtime 준비 확인 | `./scripts/check-baron-api-env.sh` | failure/warning 없이 통과 |
| 1-A | 완료 | `baron_backend` 미실행 시 복구 | Baron SSO API worktree에서 `docker compose up -d backend` | `baron_backend` running/healthy |
| 1-B | 완료 | Ory/UserFront runtime 확인 및 복구 | `docker ps -a`, 필요 시 Ory/UserFront 컨테이너 시작 | `ory_kratos`, `ory_hydra`, `ory_keto`, `ory_oathkeeper`, `ory_postgres`, `baron_userfront` running |
| 2 | 완료 | host 기준 authenticated API smoke 확인 | `./scripts/api-smoke.sh` | phone-login/직원목록/조직도 HTTP 200 |
| 3 | 완료 | Flutter/Docker가 인식하는 device 확인 | `./scripts/flutter-docker.sh devices` | Android target이 표시되거나 부재 원인 확인 |
| 3-A | 완료 | host/WSL ADB 상태 확인 | `adb devices` 또는 `which adb` | ADB 설치/연결 상태 확인 |
| 3-B | 완료 | Android target 준비 | Windows Android Studio emulator 실행 + WSL/Docker에서 ADB 접근 구성 | Flutter devices에 Android target 표시 |
| 4 | 대기 | 실기기용 API 주소 결정 | `scripts/.env.android-device.local` | 실기기에서 접근 가능한 `TDC114_API_BASE` 확정 |
| 4-A | 완료 | Android target Docker ADB 인식 확인 | `ADB_SERVER_SOCKET=tcp:172.21.128.1:5037 ./scripts/flutter-docker.sh devices` | 실기기 또는 fallback emulator 표시 |
| 5 | 완료 | emulator integration test 실행 | `TDC114_SMOKE_ENV_FILE=scripts/.env.android-emulator.local TDC114_ADB_CONNECT_ADDRESS=172.21.128.1:5555 ./scripts/integration_tests.sh` | `+3: All tests passed!` |
| 5-B | 완료 | 로그인 완료 가정 기능점검 | `TDC114_SMOKE_ASSUME_LOGGED_IN=1` 기반 세션 bootstrap 후 emulator integration test 실행 | 앱이 post-login 상태에서 직원검색/즐겨찾기/상세 액션 smoke를 통과 |
| 5-A | 완료 | Docker local ADB 방식 검증 | Windows `5555` portproxy + Docker 내부 `adb connect` | integration test runner가 VM service에 연결 |
| 6 | 대기 | 실기기 연결 확인 | `adb devices` 또는 Flutter devices | device 상태 표시 |
| 7 | 대기 | 실기기 API 접근 방식 결정 | `adb reverse tcp:5000 tcp:5000` 또는 PC LAN IP | 실기기 브라우저/API 접근 가능 |
| 8 | 대기 | 실기기 integration test 실행 | `TDC114_SMOKE_ENV_FILE=scripts/.env.android-device.local ./scripts/integration_tests.sh` | 로그인 후 직원목록 진입 |
| 9 | 대기 | 플랫폼 액션 수동 smoke | 실제 앱에서 전화/문자 버튼 확인 | 전화/문자 intent가 정상 호출 |
| 10 | 대기 | 즐겨찾기 유지 수동 smoke | 즐겨찾기 토글 후 앱 재실행 | 즐겨찾기 상태 유지 |
| 11 | 대기 | 결과 기록 | 테스트 로그 업데이트 | 성공/실패와 후속 조치 기록 |

## 4. 환경 파일 예시

### 4.1 Host smoke

기본 파일:

```text
scripts/.env.smoke.local
```

예시:

```bash
TDC114_API_BASE=http://127.0.0.1:5000
TDC114_SMOKE_PHONE=010xxxxxxxx
```

### 4.2 Android emulator fallback

기본 파일:

```text
scripts/.env.android-emulator.local
```

예시:

```bash
TDC114_API_BASE=http://10.0.2.2:5000
TDC114_SMOKE_PHONE=010xxxxxxxx
```

### 4.3 Android 실기기

`adb reverse`를 쓰는 경우:

```bash
TDC114_API_BASE=http://127.0.0.1:5000
TDC114_SMOKE_PHONE=010xxxxxxxx
```

PC LAN IP를 쓰는 경우:

```bash
TDC114_API_BASE=http://<PC_LAN_IP>:5000
TDC114_SMOKE_PHONE=010xxxxxxxx
```

## 5. 실패별 분기

| 증상 | 의미 | 다음 조치 |
| --- | --- | --- |
| `No supported devices connected.` | Flutter가 실행 가능한 Android target을 못 봄 | USB 디버깅 실기기 확인, 필요 시 Android Studio emulator fallback 실행, Docker/ADB 접근 방식 확인 |
| `Integration tests and unit tests cannot be run in a single invocation.` | 현재 Flutter 버전에서 Android integration을 `flutter test`로 호출함 | `flutter drive --driver=test_driver/integration_driver.dart --target=integration_test/...` 경로로 전환 |
| Linux desktop만 표시됨 | WSL/Docker Flutter는 보이지만 앱에 Linux runner가 없음 | Android target 연결 또는 별도 desktop runner 추가 검토 |
| `adb: command not found` | WSL에 Android platform-tools가 없음 | Windows Android Studio platform-tools를 PATH로 연결하거나 WSL에 Android SDK platform-tools 설치 |
| Windows `adb -a -P 5037 nodaemon server`에서 10048 | 기존 ADB server 또는 다른 프로세스가 5037 포트를 이미 사용 중 | `Get-Process adb`/`Stop-Process`, `netstat -ano | findstr :5037`, `taskkill /PID ... /F` 후 재시도 |
| `WebSocketChannelException`, `127.0.0.1:<dynamic port>` connection refused | remote Windows ADB server가 만든 VM service forward가 Docker container localhost와 맞지 않음 | Windows emulator adbd `5555`를 portproxy로 노출하고 Docker 내부 local ADB server에서 `adb connect` 방식 검증 |
| Docker local ADB가 `unauthorized` | Docker container의 ADB key가 emulator에서 승인된 Windows ADB key와 다름 | Windows 사용자 ADB key를 git ignored `.android-adb/`에 복사하고 Docker `/root/.android`로 마운트 |
| integration test 로그인 화면/validation은 통과하지만 real API login test 실패 | 앱/API 문제 또는 backend runtime 중단 가능 | 먼저 `./scripts/api-smoke.sh`로 host authenticated smoke 재확인, 502면 Baron/Ory runtime 복구 |
| API smoke는 통과하지만 integration test login 실패 | Android 런타임에서 API base URL 접근 실패 가능 | emulator는 `10.0.2.2`, 실기기는 `adb reverse` 또는 PC LAN IP 확인 |
| HTTP cleartext 차단 | Android 앱이 `http://` 접근을 막을 수 있음 | Android network security config 또는 manifest 확인 |
| phone-login 401 | 테스트 전화번호가 Baron SSO 등록자와 불일치 | env 파일의 전화번호와 Baron SSO 등록 상태 확인 |
| phone-login 503 | Baron SSO/Ory/Kratos 세션 발급 문제 | backend 로그 확인, 인증 민감 영역으로 별도 검토 |
| backend는 running인데 `kratos`, `keto`, `hydra` DNS 실패 | Ory runtime 컨테이너가 중지됨 | Ory/UserFront 컨테이너 시작 후 runtime 점검 재실행 |
| employee/orgchart 401/403 | token/session/권한 문제 | 앱 세션 저장/전달, backend auth middleware 확인 |

## 6. 현재 실행 메모

- 2026-07-03: 문서 생성. 다음 단계는 1단계 `check-baron-api-env.sh` 실행이다.
- 2026-07-03: 1단계 실행 결과 `baron_backend`가 running 상태가 아니어서 1-A 복구 단계를 추가했다.
- 2026-07-03: 1-A에서 `docker compose up -d backend` 실행 후 1단계 재검증 통과. `baron_backend`, `baron_gateway` running 확인.
- 2026-07-03: 2단계 API smoke에서 phone-login 503 발생. backend 로그에서 `kratos`, `keto`, `hydra`, `oathkeeper` DNS 실패 확인. 1-B Ory/UserFront 복구 단계를 추가했다.
- 2026-07-03: 1-B에서 Ory/UserFront 컨테이너를 시작했다. `baron_backend`, `baron_userfront`, `baron_gateway`, Ory 핵심 컨테이너 running 확인.
- 2026-07-03: 2단계 API smoke 재실행 통과. phone-login, employee list, tenant list, orgchart 모두 HTTP 200.
- 2026-07-03: 3단계 `./scripts/flutter-docker.sh devices` 실행 결과 Docker Flutter는 `Linux desktop`만 인식하고 Android emulator/device는 인식하지 못했다. 3-A ADB 상태 확인 단계를 추가했다.
- 2026-07-03 08:11 KST: 3-A 확인 결과 WSL에 `adb`가 설치되어 있지 않다. `./scripts/integration_tests.sh`는 Linux desktop만 발견했지만 앱에 Linux runner가 없어 `No supported devices connected.`로 종료했다. 3-B Android target 준비 단계가 필요하다.
- 2026-07-03 오전: Windows Android Studio에서 `Medium Phone` Android 15 API 35 emulator를 생성하고 Windows `adb.exe devices`에서 `emulator-5554 device`를 확인했다.
- 2026-07-03 오전: Windows `adb -a -P 5037 nodaemon server`는 기존 ADB server 자동 재기동으로 `10048` 오류가 반복되어 `netsh interface portproxy` 방식으로 전환했다.
- 2026-07-03 오전: 관리자 PowerShell에서 `0.0.0.0:5037 -> 127.0.0.1:5037` portproxy와 방화벽 rule을 추가했다. WSL에서 `172.21.128.1:5037` 연결 성공, Docker Flutter 내부 `adb devices`에서 `emulator-5554 device` 확인.
- 2026-07-03 10:22 KST: `scripts/integration_tests.sh`를 실시간 출력 방식으로 개선한 뒤 emulator integration test를 재실행했다. APK 빌드/설치는 성공했지만 test loading 단계에서 `WebSocketChannelException`, `127.0.0.1:<dynamic port>` connection refused로 실패했다. remote Windows ADB server의 VM service port forward가 Docker container localhost와 맞지 않는 구조로 판단하고 5-A를 추가했다.
- 2026-07-03 11:06 KST: Windows 관리자 PowerShell에서 `0.0.0.0:5555 -> 127.0.0.1:5555` portproxy와 방화벽 rule을 추가했다. Docker local ADB 방식에서 최초 `unauthorized`가 발생했으나 Windows 사용자 ADB key를 git ignored `.android-adb/`에 복사하고 Docker `/root/.android`로 마운트해 `172.21.128.1:5555 device` 상태를 확보했다.
- 2026-07-03 11:06 KST: Docker local ADB 방식으로 integration test를 재실행했다. 최초 real API login test 실패는 Baron/Ory runtime 중단에 따른 `api-smoke.sh` 502와 연관됨을 확인했고, Ory/UserFront 및 backend 재시작 후 authenticated API smoke 통과, 최종 integration test `+3: All tests passed!`를 확인했다.
- 2026-07-06: 신규 링크 로그인 전환 이후에는 local 승인 완료 E2E가 막힐 수 있으므로, Android target 기능점검은 `TDC114_SMOKE_ASSUME_LOGGED_IN=1`을 이용한 post-login 세션 seed 경로를 함께 사용한다.
- 2026-07-06: local Baron SSO runtime에 테스트 번호 `010-9136-5338`용 identity와 local user를 맞춘 뒤 legacy `phone-login` HTTP 200, headless 로그인 시작 응답, `link/poll` pending 상태까지 확인했다.
- 2026-07-06: 로그인 완료 가정 기능점검 재시도에서는 host `api-smoke.sh`는 다시 통과했지만, `172.21.128.1:5555`는 `offline`, `172.21.128.1:5037` 경로는 `protocol fault`라 Android target 연결이 실패했다. 현재 blocker는 앱/API가 아니라 Windows emulator 또는 ADB/portproxy 상태다.

## 7. 3-B Android target 준비 상세 절차

아래 중 하나를 선택한다.

### 7.0 현재 WSL 확인 결과

2026-07-03 현재 확인한 내용:

- WSL 내부 `adb` 명령은 없다.
- WSL 내부 `java` 명령은 없다.
- WSL 내부 `sdkmanager`, `emulator` 명령은 없다.
- `ANDROID_HOME`, `ANDROID_SDK_ROOT` 환경 변수는 설정되어 있지 않다.
- `/dev/kvm` 장치가 확인되지 않아 WSL 내부 Android emulator 가속 실행 가능성이 낮다.
- 일반적인 Windows Android SDK 경로(`/mnt/c/Users/*/AppData/Local/Android/Sdk/platform-tools`)가 WSL에서 바로 발견되지 않았다.
- WSL에서 `powershell.exe`를 호출해 Windows 경로를 자동 탐색하려 했으나 현재 세션에서는 `UtilBindVsockAnyPort` 오류로 실행되지 않았다.

따라서 캡쳐처럼 Ubuntu/WSL 내부에 Android SDK, emulator, AVD를 직접 설치하는 경로는 현재 즉시 진행 가능하지 않다. 진행하려면 Java, Android command-line tools, platform-tools, emulator, system image, KVM/GUI 조건을 새로 맞춰야 한다. 더 안정적인 다음 단계는 Windows에서 Android Studio/SDK 설치 여부와 `adb.exe` 위치를 직접 확인하는 것이다.

### 7.0-A Ubuntu/WSL 내부 emulator 경로 판단

캡쳐의 Ubuntu 설치 방식은 아래 조건이 모두 충족될 때만 추천한다.

1. WSL에서 `/dev/kvm`이 보인다.
2. WSLg 또는 별도 X server로 emulator GUI 표시가 가능하다.
3. Java 11 이상과 Android command-line tools 설치가 가능하다.
4. `sdkmanager`, `avdmanager`, `emulator`, `adb`가 WSL 내부 PATH에 잡힌다.
5. Docker Flutter 컨테이너에서도 해당 emulator/ADB에 접근할 수 있다.

현재 환경은 1, 3, 4가 충족되지 않는다. 그래서 우선순위는 `Windows Android Studio emulator 또는 실기기 + WSL/ADB 연결` 방식으로 둔다.

### 7.1 Android emulator 사용

1. Windows Android Studio를 연다.
2. Device Manager에서 Pixel 계열 emulator를 생성하거나 기존 emulator를 시작한다.
3. Windows 터미널에서 `adb devices`로 emulator가 보이는지 확인한다.
4. WSL에서 Android platform-tools를 사용할 수 있게 한다.
   - 방법 A: Windows Android SDK `platform-tools` 경로를 WSL `PATH`에 연결한다.
   - 방법 B: WSL에 Android SDK platform-tools를 별도로 설치한다.
5. WSL에서 `adb devices`가 emulator를 표시하는지 확인한다.
6. Docker Flutter가 Android device를 볼 수 있도록 `flutter-docker.sh`의 ADB socket/device mount 필요 여부를 확인한다.

### 7.2 Android 실기기 사용

1. 휴대폰에서 개발자 옵션을 활성화한다.
2. USB 디버깅을 켠다.
3. USB로 PC에 연결하고 RSA 디버깅 허용 팝업을 승인한다.
4. Windows 또는 WSL에서 `adb devices`가 `device` 상태로 표시되는지 확인한다.
5. 실기기에서 local API 접근은 `adb reverse tcp:5000 tcp:5000` 또는 PC LAN IP 방식 중 하나를 선택한다.

### 7.3 Windows emulator + Docker local ADB server 방식

`ADB_SERVER_SOCKET=tcp:<WINDOWS_HOST_IP>:5037` 방식은 Flutter device 목록 확인과 APK 설치까지 가능했지만, integration test loading 단계에서 VM service dynamic port가 Docker container의 `127.0.0.1`로 연결되지 않는 문제가 발생했다.

다음 검증은 Docker container 내부의 local ADB server가 Windows emulator adbd에 직접 붙는 방식으로 진행한다.

1. Windows 관리자 PowerShell에서 emulator adbd port를 노출한다.

```powershell
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=5555 connectaddress=127.0.0.1 connectport=5555
netsh advfirewall firewall add rule name="ADB emulator 5555 for WSL" dir=in action=allow protocol=TCP localport=5555
netsh interface portproxy show v4tov4
```

2. WSL에서 `5555` 연결을 확인한다.

```bash
nc -vz 172.21.128.1 5555
```

3. Docker Flutter container 내부에서 local ADB server로 emulator에 직접 연결한다.

```bash
docker run --rm ghcr.io/cirruslabs/flutter:stable sh -lc 'adb connect 172.21.128.1:5555 && adb devices'
```

4. 이 방식에서 device가 표시되면 `scripts/flutter-docker.sh`에 `TDC114_ADB_CONNECT_ADDRESS` 같은 optional env를 추가해 테스트 실행 전 `adb connect`를 수행하도록 보강한다.

5. Docker ADB가 `unauthorized`로 표시되면 Windows에서 이미 승인된 ADB key를 local ignored directory에 복사한다.

```bash
mkdir -p .android-adb
cp /mnt/c/Users/user/.android/adbkey .android-adb/adbkey.new
cp /mnt/c/Users/user/.android/adbkey.pub .android-adb/adbkey.pub.new
mv -f .android-adb/adbkey.new .android-adb/adbkey
mv -f .android-adb/adbkey.pub.new .android-adb/adbkey.pub
chmod 600 .android-adb/adbkey
```

6. 최종 실행 명령:

```bash
TDC114_SMOKE_ENV_FILE=scripts/.env.android-emulator.local \
TDC114_ADB_CONNECT_ADDRESS=172.21.128.1:5555 \
./scripts/integration_tests.sh
```

현재 환경의 통과 기준 출력:

```text
+3: All tests passed!
```

### 7.4 로그인 완료 가정 기능점검

신규 링크 로그인 흐름에서는 local runtime에서 실제 승인 완료까지 항상 검증할 수 있는 것이 아니므로, Android target 기능점검은 아래 보조 경로를 사용한다.

1. 기본은 mock 세션 seed를 사용한다.
2. legacy 호환 점검이 꼭 필요할 때만 host 기준 `phone-login` API로 유효 세션을 1회 발급받는다.
3. 해당 세션 또는 mock user 정보를 Flutter app 시작 전에 `SharedPreferences`에 seed 한다.
4. 앱이 `AuthGate`에서 로그인 화면 대신 `직원검색`으로 바로 진입하는지 확인한다.
5. 직원 목록, 즐겨찾기, 직원 상세, 전화/문자 버튼 노출을 integration test로 점검한다.
6. local runtime이 유효 세션을 발급하지 못하면 mock directory 모드로 fallback 하여 post-login UI 기능만 별도로 점검한다.

실행 예시:

```bash
TDC114_SMOKE_ENV_FILE=scripts/.env.android-emulator.local \
TDC114_SMOKE_ASSUME_LOGGED_IN=1 \
TDC114_ADB_CONNECT_ADDRESS=172.21.128.1:5555 \
./scripts/integration_tests.sh
```

주의:

- 이 경로는 "로그인 완료 이후 앱 기능" 점검용이다.
- 실제 `headless phone-login -> 승인 -> link/poll 성공` 자체를 대체하지는 않는다.
- local `phone-login` bootstrap이 `401 login_failed`이면 자동으로 mock directory fallback을 사용한다.
