feat(stats): buffer visits in memory and expose POST /api/visit + /api/stats
This commit is contained in:
1 parent
cdd11823b9
commit
3c16caac1a
8 files changed
+905
-5
No files matched your search
@@ -477,6 +477,65 @@ def test_about_payload():
|
||||
db.close()
|
||||
|
||||
|
||||
def test_stats_query():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db, q = setup(tmp)
|
||||
try:
|
||||
empty = q.stats(days=7)
|
||||
assert empty["today"] == "2026-10-31"
|
||||
assert empty["today_pv"] == 0 and empty["today_uv"] == 0
|
||||
assert len(empty["series"]["dates"]) == 7
|
||||
assert empty["series"]["dates"][-1] == "2026-10-31"
|
||||
assert empty["total_pv"] == 0 and empty["total_uv"] == 0
|
||||
assert empty["top_pages"] == []
|
||||
assert empty["enabled"] is True
|
||||
assert empty["pending"] is False
|
||||
|
||||
def insert(conn, day, ip, path, hits, first, last):
|
||||
conn.execute(
|
||||
"INSERT INTO visit(stat_date, ip, path, hits, first_at, last_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?)",
|
||||
(day, ip, path, hits, first, last),
|
||||
)
|
||||
|
||||
db.write(lambda conn: [
|
||||
insert(conn, "2026-10-31", "1.1.1.1", "/home", 3, 1, 2),
|
||||
insert(conn, "2026-10-31", "2.2.2.2", "/home", 1, 1, 1),
|
||||
insert(conn, "2026-10-31", "1.1.1.1", "/videos", 2, 1, 1),
|
||||
insert(conn, "2026-10-30", "1.1.1.1", "/home", 5, 1, 1),
|
||||
insert(conn, "2026-09-01", "9.9.9.9", "/home", 100, 1, 1),
|
||||
])
|
||||
stats = q.stats(days=7)
|
||||
assert stats["today_pv"] == 6
|
||||
assert stats["today_uv"] == 2
|
||||
assert stats["total_pv"] == 11 # 今天 6 + 昨天 5,区间外不计
|
||||
assert stats["total_uv"] == 2
|
||||
assert stats["series"]["pv"][-1] == 6
|
||||
assert stats["series"]["pv"][-2] == 5
|
||||
assert stats["series"]["uv"][-1] == 2
|
||||
pages = {page["path"]: page for page in stats["top_pages"]}
|
||||
assert pages["/home"]["pv"] == 9 and pages["/home"]["uv"] == 2
|
||||
assert pages["/videos"]["pv"] == 2 and pages["/videos"]["uv"] == 1
|
||||
assert stats["top_pages"][0]["path"] == "/home"
|
||||
|
||||
# 内存缓冲合并:不同键相加,重叠键去重合并
|
||||
pending = [
|
||||
{"stat_date": "2026-10-31", "ip": "3.3.3.3",
|
||||
"path": "/about", "hits": 4, "first_at": 1, "last_at": 1},
|
||||
{"stat_date": "2026-10-31", "ip": "1.1.1.1",
|
||||
"path": "/home", "hits": 1, "first_at": 3, "last_at": 3},
|
||||
]
|
||||
merged = q.stats(days=7, pending=pending)
|
||||
assert merged["today_pv"] == 11
|
||||
assert merged["today_uv"] == 3
|
||||
assert merged["pending"] is True
|
||||
pages = {page["path"]: page for page in merged["top_pages"]}
|
||||
assert pages["/about"]["pv"] == 4
|
||||
assert pages["/home"]["pv"] == 10
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def main_test():
|
||||
test_overview()
|
||||
test_video_listing_filters_and_sorting()
|
||||
@@ -487,9 +546,10 @@ def main_test():
|
||||
test_duration_efficiency_queries()
|
||||
test_year_filter_and_published_sort()
|
||||
test_about_payload()
|
||||
test_stats_query()
|
||||
test_fans_custom_range_modes()
|
||||
test_fans_candidates_system_and_export()
|
||||
print("OK: Web 查询层总览/榜单/详情/UP/时长效率/粉丝/候选/系统测试全部通过")
|
||||
print("OK: Web 查询层总览/榜单/详情/UP/时长效率/粉丝/候选/系统/访问统计测试全部通过")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user