o2o-negosium-original/negodata/backend/tests/test_company_user.py
Mina Choi 82076e138e [test] negodata: 백엔드 테스트 스위트 구축 + 공통 픽스처(conftest) 정비
- test DB 세션마다 자동 create/drop (팀원은 Postgres만 있으면 pytest 한 방)
- auth_headers 시드 픽스처(무인증 /auth/create 제거 대응) + other_company_id
- 커버: 회사 스코프(견적·상품·협력사·대시보드·세팅), 견적 마감 재견적 O/X + 알림,
  견적 생성·목표가, 알림함 읽기, 회사유저 OWNER 게이팅, 기존 파일 검증/기대결과 주석 정비

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:06:55 +09:00

89 lines
4.0 KiB
Python

"""직원 계정 관리(/v1/company/user/*) 테스트 — '최고관리자만' 쓸 수 있고, '자기 회사'만 다뤄지는지 확인.
- 일반 직원 계정으로는 이 기능을 못 쓴다(HTTP 403 으로 막힘).
- 최고관리자는 자기 회사 직원만 목록에 보이고, 생성도 자기 회사로 된다(남의 회사 직원은 안 보임).
- 로그인 아이디는 전체에서 유일해야 해서, 같은 아이디로 또 만들면 거부된다(코드 1201).
"""
import uuid
from sqlalchemy import text
from common.enums import UserRole, UserStatus
async def test_regular_user_forbidden_on_owner_endpoints(client, auth_headers):
"""검증: 일반 USER 토큰으로 최고관리자 전용 엔드포인트(list·create) 호출.
기대결과: 둘 다 HTTP 403(RequireOwner 차단)."""
h = await auth_headers("plainuser") # role=USER 기본
r = await client.get("/v1/company/user/list", headers=h)
assert r.status_code == 403
r = await client.post(
"/v1/company/user/create", json={"id": "x", "password": "p", "name": "n"}, headers=h
)
assert r.status_code == 403
async def test_owner_lists_only_own_company_users(client, auth_headers, company_id, other_company_id, db_engine):
"""검증: 회사A OWNER + A직원 + B직원(타사)을 두고 OWNER 가 유저 목록 조회.
기대결과: 본인·A직원은 목록에 있고 타사(B) 직원은 없음(회사 스코프)."""
owner_h = await auth_headers("ownerA", role=UserRole.OWNER.value) # 회사 A owner
await _seed_user(db_engine, company_id, "empA") # 같은 회사 직원
await _seed_user(db_engine, other_company_id, "empB") # 다른 회사 직원
r = await client.get("/v1/company/user/list", headers=owner_h)
ids = {u["id"] for u in r.json()["users"]}
assert "ownerA" in ids # 본인
assert "empA" in ids # 자기 회사 직원
assert "empB" not in ids # 타사 직원은 안 보임
async def test_owner_creates_user_in_own_company(client, auth_headers):
"""검증: OWNER 가 직원 계정을 생성한 뒤 목록 조회.
기대결과: 생성 success=True, 생성한 유저가 자기 회사 목록에 노출."""
owner_h = await auth_headers("ownerC", role=UserRole.OWNER.value)
r = await client.post(
"/v1/company/user/create",
json={"id": "newemp", "password": "pw1234", "name": "직원"},
headers=owner_h,
)
assert r.json()["result"]["success"] is True
r = await client.get("/v1/company/user/list", headers=owner_h)
ids = {u["id"] for u in r.json()["users"]}
assert "newemp" in ids
async def test_duplicate_login_id_rejected(client, auth_headers):
"""검증: OWNER 가 같은 로그인 ID 로 직원 계정을 2번 생성.
기대결과: 1번째 success=True, 2번째 success=False, code=1201(ACCOUNT_ALREADY_EXIST)."""
owner_h = await auth_headers("ownerD", role=UserRole.OWNER.value)
r1 = await client.post(
"/v1/company/user/create", json={"id": "dup", "password": "pw1234", "name": "n"}, headers=owner_h
)
assert r1.json()["result"]["success"] is True
r2 = await client.post(
"/v1/company/user/create", json={"id": "dup", "password": "pw5678", "name": "n2"}, headers=owner_h
)
body = r2.json()
assert body["result"]["success"] is False
assert body["result"]["code"] == 1201
# ===== 헬퍼 (위 테스트들이 쓰는 도우미) =====
async def _seed_user(engine, company_id, login_id, *, role=UserRole.USER.value):
"""로그인 안 하는 소속 직원 시드(목록 스코프 확인용). 비번은 임의값."""
async with engine.begin() as conn:
await conn.execute(
text(
"INSERT INTO users (user_id, company_id, id, password, name, status, role, last_accessed_at) "
"VALUES (:uid, :cid, :id, 'x', 'n', :status, :role, now())"
),
{"uid": uuid.uuid4(), "cid": uuid.UUID(company_id), "id": login_id,
"status": UserStatus.ACTIVE.value, "role": role},
)