mirror of
https://github.com/superdesigndev/treg.git
synced 2026-10-02 03:24:35 +08:00
119 lines
6.1 KiB
Python
119 lines
6.1 KiB
Python
"""Owned-team limits through the same HTTP routes used by the dashboard and CLI."""
|
|
import asyncio
|
|
|
|
|
|
async def test_eleventh_owned_team_is_refused(clients):
|
|
# The authenticated fixture already owns its first team.
|
|
for i in range(9):
|
|
r = await clients.post('/orgs', json={'name': f'team-{i}'})
|
|
assert r.status_code == 200, r.text
|
|
before = (await clients.get('/orgs')).json()
|
|
r = await clients.post('/orgs', json={'name': 'eleventh'})
|
|
assert r.status_code == 403, r.text
|
|
assert '10 teams' in r.json()['detail']
|
|
assert (await clients.get('/orgs')).json() == before
|
|
|
|
|
|
async def test_concurrent_creations_share_the_last_slot(clients):
|
|
for i in range(8):
|
|
assert (await clients.post('/orgs', json={'name': f'team-{i}'})).status_code == 200
|
|
responses = await asyncio.gather(*(
|
|
clients.post('/orgs', json={'name': f'racing-{i}'}) for i in range(4)
|
|
))
|
|
assert sorted(r.status_code for r in responses) == [200, 403, 403, 403]
|
|
assert len((await clients.get('/orgs')).json()) == 10
|
|
|
|
|
|
async def test_deletion_frees_a_slot_and_legacy_first_team_counts(clients):
|
|
first = (await clients.post('/users', json={'email': 'legacy-limit@example.org'})).json()
|
|
headers = {'X-Treg-Token': first['token']}
|
|
for i in range(9):
|
|
r = await clients.post('/orgs', headers=headers, json={'name': f'legacy-{i}'})
|
|
assert r.status_code == 200
|
|
last = r.json()
|
|
assert (await clients.post('/orgs', headers=headers, json={'name': 'blocked'})).status_code == 403
|
|
deleted = await clients.delete(f"/orgs/{last['org_id']}", params={'confirm': last['org']},
|
|
headers={'X-Treg-Token': last['token']})
|
|
assert deleted.status_code == 200, deleted.text
|
|
assert (await clients.post('/orgs', headers=headers, json={'name': 'replacement'})).status_code == 200
|
|
assert (await clients.post('/orgs', headers=headers, json={'name': 'blocked-again'})).status_code == 403
|
|
|
|
|
|
async def test_joining_does_not_count_but_promotion_does(clients):
|
|
from sqlmodel import select
|
|
from treg.infra.db import session_maker
|
|
from treg.models import User
|
|
|
|
other = (await clients.post('/users', json={'email': 'other-owner@example.org'})).json()
|
|
other_headers = {'X-Treg-Token': other['token']}
|
|
inv = await clients.post(f"/orgs/{other['org_id']}/invites", headers=other_headers,
|
|
json={'email': 'tim@superdesign.dev', 'role': 'member'})
|
|
accepted = await clients.post('/invites/accept', json={
|
|
'code': inv.json()['code'], 'email': 'tim@superdesign.dev'})
|
|
assert accepted.status_code == 200, accepted.text
|
|
for i in range(9):
|
|
assert (await clients.post('/orgs', json={'name': f'owned-{i}'})).status_code == 200
|
|
assert len((await clients.get('/orgs')).json()) == 11
|
|
async with session_maker() as db:
|
|
uid = (await db.execute(select(User.id).where(User.email == 'tim@superdesign.dev'))).scalar_one()
|
|
promoted = await clients.patch(f"/orgs/{other['org_id']}/members/{uid}",
|
|
headers=other_headers, json={'role': 'owner'})
|
|
assert promoted.status_code == 403, promoted.text
|
|
assert (await clients.get('/tools', headers={'X-Treg-Token': accepted.json()['token']})).status_code == 200
|
|
|
|
|
|
async def test_demo_cannot_bypass_limit_but_existing_demo_can_be_reused(clients):
|
|
for i in range(8):
|
|
assert (await clients.post('/orgs', json={'name': f'owned-{i}'})).status_code == 200
|
|
demo = await clients.post('/onboard/demo', json={'team_name': 'Demo'})
|
|
assert demo.status_code == 200, demo.text
|
|
assert (await clients.post('/orgs', json={'name': 'eleventh'})).status_code == 403
|
|
reused = await clients.post('/onboard/demo', json={'team_name': 'Demo again'})
|
|
assert reused.status_code == 200, reused.text
|
|
assert len((await clients.get('/orgs')).json()) == 10
|
|
|
|
|
|
async def test_demo_refused_at_ten_and_existing_excess_teams_preserved(clients):
|
|
from sqlmodel import select
|
|
from treg.infra.db import session_maker
|
|
from treg.models import Membership, Org, User
|
|
|
|
# Seed the pre-upgrade state, which normal creation can no longer produce.
|
|
async with session_maker() as db:
|
|
uid = (await db.execute(select(User.id).where(User.email == 'tim@superdesign.dev'))).scalar_one()
|
|
for i in range(11):
|
|
org = Org(name=f'Existing {i}', slug=f'existing-{i}')
|
|
db.add(org)
|
|
await db.flush()
|
|
db.add(Membership(user_id=uid, org_id=org.id, role='owner', token_hash=f'old-{i}'))
|
|
await db.commit()
|
|
before = (await clients.get('/orgs')).json()
|
|
assert len(before) == 12
|
|
assert (await clients.post('/orgs', json={'name': 'new'})).status_code == 403
|
|
assert (await clients.post('/onboard/demo', json={'team_name': 'demo'})).status_code == 403
|
|
assert (await clients.get('/orgs')).json() == before
|
|
assert (await clients.get('/tools')).status_code == 200
|
|
|
|
|
|
async def test_promotion_and_creation_compete_for_same_slot(clients):
|
|
from sqlmodel import select
|
|
from treg.infra.db import session_maker
|
|
from treg.models import User
|
|
|
|
other = (await clients.post('/users', json={'email': 'race-owner@example.org'})).json()
|
|
headers = {'X-Treg-Token': other['token']}
|
|
inv = await clients.post(f"/orgs/{other['org_id']}/invites", headers=headers,
|
|
json={'email': 'tim@superdesign.dev'})
|
|
assert (await clients.post('/invites/accept', json={
|
|
'code': inv.json()['code'], 'email': 'tim@superdesign.dev'})).status_code == 200
|
|
for i in range(8):
|
|
assert (await clients.post('/orgs', json={'name': f'before-race-{i}'})).status_code == 200
|
|
async with session_maker() as db:
|
|
uid = (await db.execute(select(User.id).where(User.email == 'tim@superdesign.dev'))).scalar_one()
|
|
results = await asyncio.gather(
|
|
clients.post('/orgs', json={'name': 'last-slot'}),
|
|
clients.patch(f"/orgs/{other['org_id']}/members/{uid}", headers=headers, json={'role': 'owner'}),
|
|
)
|
|
assert sorted(r.status_code for r in results) == [200, 403]
|
|
assert sum(t['role'] == 'owner' for t in (await clients.get('/orgs')).json()) == 10
|