2.0.0-rc2: Achievements Refactored & Admin improved.

This commit is contained in:
2026-08-09 01:34:20 +08:00
parent 3874bf57a9
commit 63a0751aba
29 changed files with 2143 additions and 355 deletions
+163 -2
View File
@@ -46,6 +46,7 @@ class ApplicationIntegrationTests(unittest.TestCase):
'/matches/',
'/reports/',
'/awards/',
'/discover/',
'/players/',
f'/players/{self.roster_ids[0]}',
'/teams/',
@@ -59,6 +60,35 @@ class ApplicationIntegrationTests(unittest.TestCase):
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 100)
def test_discovery_filters_and_player_medals_render(self):
response = self.client.get('/discover/')
self.assertEqual(response.status_code, 200)
for label in ('趣味发现', '表现勋章墙', '勋章总榜'):
self.assertIn(label.encode('utf-8'), response.data)
response = self.client.get('/discover/?tone=negative')
self.assertEqual(response.status_code, 200)
self.assertIn('低谷收藏家'.encode('utf-8'), response.data)
response = self.client.get('/discover/?dimension=elo')
self.assertEqual(response.status_code, 200)
self.assertIn(b'ELO Medal', response.data)
l3 = sqlite3.connect(Config.DB_L3_PATH)
try:
medal_player = l3.execute(
"""
SELECT steam_id_64
FROM dm_performance_medals
ORDER BY medal_rank
LIMIT 1
"""
).fetchone()[0]
finally:
l3.close()
response = self.client.get(f'/players/{medal_player}')
self.assertIn(b'Map & ELO Medals', response.data)
def test_match_detail_contains_post_match_report(self):
l3 = sqlite3.connect(Config.DB_L3_PATH)
try:
@@ -103,10 +133,11 @@ class ApplicationIntegrationTests(unittest.TestCase):
def test_admin_integrity_page_and_json_render(self):
with self.client.session_transaction() as session:
session['is_admin'] = True
session['_csrf_token'] = 'test-csrf'
response = self.client.get('/admin/data-integrity')
self.assertEqual(response.status_code, 200)
self.assertIn('数据完整性中心'.encode('utf-8'), response.data)
self.assertIn('数据质量中心'.encode('utf-8'), response.data)
response = self.client.get('/admin/data-integrity?format=json')
self.assertEqual(response.status_code, 200)
@@ -120,13 +151,66 @@ class ApplicationIntegrationTests(unittest.TestCase):
response = self.client.get('/admin/import-match')
self.assertEqual(response.status_code, 200)
self.assertIn('比赛数据导入'.encode('utf-8'), response.data)
self.assertIn('比赛导入'.encode('utf-8'), response.data)
def test_admin_console_pages_share_navigation_and_real_data(self):
with self.client.session_transaction() as session:
session['is_admin'] = True
session['_csrf_token'] = 'test-csrf'
pages = {
'/admin/': ('运营总览', '完整数据流水线'),
'/admin/jobs': ('作业中心', '执行记录'),
'/admin/sql': ('只读查询控制台', 'Database Objects'),
'/admin/system': ('系统与存储', '回滚快照'),
}
for path, labels in pages.items():
with self.subTest(path=path):
response = self.client.get(path)
self.assertEqual(response.status_code, 200)
self.assertIn('YRTV'.encode('utf-8'), response.data)
for label in labels:
self.assertIn(label.encode('utf-8'), response.data)
def test_admin_sql_is_read_only_and_csrf_protected(self):
with self.client.session_transaction() as session:
session['is_admin'] = True
session['_csrf_token'] = 'test-csrf'
response = self.client.post(
'/admin/sql',
data={
'_csrf_token': 'test-csrf',
'db_name': 'l2',
'query': 'SELECT COUNT(*) AS matches FROM fact_matches',
},
)
self.assertEqual(response.status_code, 200)
self.assertIn(b'matches', response.data)
self.assertIn(b'208', response.data)
response = self.client.post(
'/admin/sql',
data={
'_csrf_token': 'test-csrf',
'db_name': 'l2',
'query': 'DELETE FROM fact_matches',
},
)
self.assertEqual(response.status_code, 200)
self.assertIn(b'Only SELECT queries are allowed', response.data)
response = self.client.post(
'/admin/trigger_etl',
headers={'Accept': 'application/json'},
)
self.assertEqual(response.status_code, 400)
def test_duplicate_match_upload_is_rejected_without_starting_job(self):
from database.paths import L1_DB
with self.client.session_transaction() as session:
session['is_admin'] = True
session['_csrf_token'] = 'test-csrf'
with sqlite3.connect(str(L1_DB)) as db:
raw = db.execute(
"""
@@ -142,6 +226,7 @@ class ApplicationIntegrationTests(unittest.TestCase):
response = self.client.post(
'/admin/import-match',
data={
'_csrf_token': 'test-csrf',
'capture': (
upload,
'iframe_network.json',
@@ -178,6 +263,8 @@ class ApplicationIntegrationTests(unittest.TestCase):
):
with self.subTest(label=label):
self.assertIn(label.encode('utf-8'), response.data)
self.assertIn(b'x-data="{ selected: \'last_20\' }"', response.data)
self.assertNotIn(b'periods: [{', response.data)
def test_profile_period_api_and_trend_window(self):
steam_id = self.roster_ids[0]
@@ -699,6 +786,80 @@ class DatabaseGovernanceTests(unittest.TestCase):
self.assertNotIn((award_type, period_key), seen)
seen.add((award_type, period_key))
def test_discovery_tones_and_medal_rules(self):
l3 = sqlite3.connect(Config.DB_L3_PATH)
try:
tones = {
row[0] for row in l3.execute(
'SELECT DISTINCT tone FROM dm_discovery_insights'
)
}
medals = l3.execute(
"""
SELECT dimension_type, dimension_key, medal_rank,
medal_tier, matches
FROM dm_performance_medals
"""
).fetchall()
finally:
l3.close()
self.assertEqual(tones, {'positive', 'negative', 'fun'})
self.assertGreater(len(medals), 0)
seen = set()
expected_tiers = {1: 'gold', 2: 'silver', 3: 'bronze'}
for dimension_type, dimension_key, rank, tier, matches in medals:
key = (dimension_type, dimension_key, rank)
self.assertNotIn(key, seen)
seen.add(key)
self.assertIn(dimension_type, {'map', 'elo'})
self.assertEqual(tier, expected_tiers[rank])
self.assertGreaterEqual(matches, 5)
def test_map_gold_medal_matches_highest_eligible_rating(self):
l3 = sqlite3.connect(Config.DB_L3_PATH)
l2 = sqlite3.connect(Config.DB_L2_PATH)
web = sqlite3.connect(Config.DB_WEB_PATH)
try:
medal = l3.execute(
"""
SELECT dimension_key, steam_id_64, avg_rating
FROM dm_performance_medals
WHERE dimension_type = 'map' AND medal_rank = 1
ORDER BY dimension_key
LIMIT 1
"""
).fetchone()
roster_ids = json.loads(
web.execute(
"""
SELECT player_ids_json FROM team_lineups
WHERE is_active = 1
"""
).fetchone()[0]
)
placeholders = ','.join('?' for _ in roster_ids)
expected = l2.execute(
f"""
SELECT p.steam_id_64, AVG(p.rating) AS avg_rating
FROM fact_match_players p
JOIN fact_matches m ON m.match_id = p.match_id
WHERE p.steam_id_64 IN ({placeholders})
AND m.map_name = ?
GROUP BY p.steam_id_64
HAVING COUNT(*) >= 5
ORDER BY avg_rating DESC, AVG(p.adr) DESC, COUNT(*) DESC
LIMIT 1
""",
roster_ids + [medal[0]],
).fetchone()
finally:
l3.close()
l2.close()
web.close()
self.assertEqual(medal[1], expected[0])
self.assertAlmostEqual(medal[2], expected[1], places=8)
def test_seasons_only_include_team_matches(self):
l2 = sqlite3.connect(Config.DB_L2_PATH)
l3 = sqlite3.connect(Config.DB_L3_PATH)