46602f1933
Remove dead code identified in docs/SANITIZATION-REVIEW.md:
- app/blueprints/content_old.py and app/blueprints/playlist.py
- app/models/group.py, app/utils/nginx_config_reader.py
- orphaned templates (content_list, edit_content, upload_content,
player_page) and the related group/Template references
Result: 6 blueprints, 82 routes, no dead modules or orphan templates.
Add files that deploy.sh and docker-entrypoint.sh already require but
which were never tracked:
- https_manager.py (referenced by deploy.sh, migrate_network.sh,
docker-entrypoint.sh)
- Caddyfile.example (seeded by deploy.sh; its absence aborts deploy)
Relocate generated Graphify artifacts from graphify-out/ to
docs/graphify-out/ (110 files, no content change) and archive the
superseded docs under docs/.
Ignore hygiene:
- ignore ad-hoc .env backups (.env.bak*) — they contain live secrets
- keep the pre-sanitization snapshots (docs/legacy code/,
docs/old_code_documentation/) on disk but out of the repo
Fix .env.example: drop a duplicated config block, genericize the
hardcoded host IP, and document HOSTNAME_INTERNAL.
109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
"""Post-sanitization verification smoke test.
|
|
|
|
Boots the app on a fresh DB, registers a player/playlist/content, and exercises
|
|
every API endpoint plus key UI routes. Fails loudly on any 5xx.
|
|
"""
|
|
import os
|
|
import tempfile
|
|
|
|
tmpdir = tempfile.mkdtemp()
|
|
db_path = os.path.join(tmpdir, 'smoke.db')
|
|
os.environ['DATABASE_URL'] = f'sqlite:///{db_path}'
|
|
|
|
from app.app import create_app
|
|
from app.extensions import db, bcrypt
|
|
from app.models import Player, Playlist, Content, User, PlayerUser, HTTPSConfig
|
|
|
|
app = create_app('testing')
|
|
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
|
|
app.config['CACHE_TYPE'] = 'simple'
|
|
|
|
with app.app_context():
|
|
db.create_all()
|
|
# prove Group/group_content are gone from metadata
|
|
tables = sorted(db.metadata.tables.keys())
|
|
print('registered tables:', tables)
|
|
assert 'group' not in tables, 'group table still registered!'
|
|
assert 'group_content' not in tables, 'group_content still registered!'
|
|
|
|
admin = User(username='smoke',
|
|
password=bcrypt.generate_password_hash('smokepw').decode('utf-8'),
|
|
role='admin')
|
|
pl = Playlist(name='Smoke PL')
|
|
db.session.add_all([admin, pl])
|
|
db.session.flush()
|
|
c = Content(filename='s.png', content_type='image', duration=5)
|
|
db.session.add(c)
|
|
db.session.flush()
|
|
pl.contents.append(c)
|
|
p = Player(name='Smoke', hostname='smoke-host', auth_code='smoke-code')
|
|
p.set_password('pw')
|
|
p.set_quickconnect_code('qc')
|
|
p.playlist_id = pl.id
|
|
db.session.add(p)
|
|
db.session.commit()
|
|
pid = p.id
|
|
code = p.auth_code
|
|
|
|
auth = {'Authorization': f'Bearer {code}'}
|
|
|
|
with app.test_client() as cl:
|
|
# public api
|
|
for url in ['/api/health', '/api/system-info', '/api/content', '/api/logs',
|
|
f'/api/player-status/{pid}',
|
|
'/api/playlists?hostname=smoke-host&quickconnect_code=qc']:
|
|
r = cl.get(url)
|
|
print(f'{r.status_code} GET {url}')
|
|
assert r.status_code < 500, f'{url} -> {r.status_code}'
|
|
# system-info must no longer expose a groups key
|
|
if url == '/api/system-info':
|
|
body = r.get_json()
|
|
assert 'groups' not in body, f'groups key still present: {body}'
|
|
print(' system-info keys:', sorted(body.keys()))
|
|
|
|
# authed api
|
|
for url in [f'/api/playlists/{pid}', f'/api/playlist-version/{pid}']:
|
|
r = cl.get(url, headers=auth)
|
|
print(f'{r.status_code} GET {url} (bearer)')
|
|
assert r.status_code < 500
|
|
|
|
r = cl.post('/api/auth/verify', json={'auth_code': code})
|
|
print(f'{r.status_code} POST /api/auth/verify')
|
|
assert r.status_code < 500
|
|
|
|
r = cl.post('/api/player-feedback', json={
|
|
'hostname': 'smoke-host', 'quickconnect_code': 'qc',
|
|
'status': 'playing', 'message': 'ok'})
|
|
print(f'{r.status_code} POST /api/player-feedback')
|
|
assert r.status_code < 500
|
|
|
|
# content listing must no longer contain group_count
|
|
body = cl.get('/api/content').get_json()
|
|
assert body['content'], 'expected seeded content'
|
|
assert 'group_count' not in body['content'][0], body['content'][0]
|
|
print(' /api/content item keys:', sorted(body['content'][0].keys()))
|
|
|
|
# login then hit UI pages
|
|
r = cl.post('/login', data={'username': 'smoke', 'password': 'smokepw'},
|
|
follow_redirects=True)
|
|
print(f'{r.status_code} POST /login')
|
|
for url in ['/', '/content/', '/content/media-library', '/players/',
|
|
'/admin/', '/admin/users', '/admin/system/info']:
|
|
r = cl.get(url, follow_redirects=True)
|
|
print(f'{r.status_code} GET {url}')
|
|
assert r.status_code < 500, f'{url} -> {r.status_code}'
|
|
|
|
# import checks
|
|
import app.utils as u
|
|
print('utils exports ok:', hasattr(u, 'get_player_status_info'))
|
|
assert not hasattr(u, 'get_group_statistics')
|
|
assert not hasattr(u, 'assign_player_to_group')
|
|
|
|
import importlib
|
|
for mod in ['app.blueprints.content', 'app.blueprints.api', 'app.utils.group_player_management',
|
|
'app.blueprints.players']:
|
|
importlib.import_module(mod)
|
|
print(f'imported {mod}')
|
|
|
|
print('\n🎉 SMOKE TEST PASSED')
|