Files
creator-hub/browser_gateway/test_event_channel.py
T
rogee 360bf96bab
douyin-release-gate / verify (push) Failing after 18m0s
feat: push Douyin events through shared WebSocket and SSE
2026-10-07 23:45:32 +08:00

96 lines
5.1 KiB
Python

import json
import threading
import unittest
import urllib.request
import urllib.error
from types import SimpleNamespace
from unittest.mock import Mock
import websocket
from browser_gateway.server.http import GatewayHTTPServer, GatewayHandler
from browser_gateway.platform.notice_polling import SubscriptionManager, NoticePollingSession
from browser_gateway.test_notice_polling import BOUNDARY, notice
class EventChannelTest(unittest.TestCase):
def setUp(self):
self.manager = SubscriptionManager(Mock())
self.sessions = {}
for alias in ('one','two'):
item = NoticePollingSession(Mock(), alias, '123', BOUNDARY, {})
self.sessions[alias] = item
self.manager._items[alias] = item
item._changed = self.manager.notify
gateway = SimpleNamespace(token='test', subscriptions=self.manager,
_alias_lock=lambda alias:threading.RLock(), _require_douyin_generation=lambda alias,value:None,
runtimes=SimpleNamespace(close=lambda:None))
self.server = GatewayHTTPServer(('127.0.0.1',0), gateway)
self.server.gateway = gateway
self.thread = threading.Thread(target=self.server.serve_forever,daemon=True); self.thread.start()
self.ws = websocket.create_connection('ws://127.0.0.1:%s/v1/channel'%self.server.server_port,
header=['Authorization: Bearer test'],timeout=2)
def tearDown(self):
self.ws.close();self.server.shutdown();self.server.server_close();self.thread.join(2)
def send(self,kind,alias='one',**values):
self.ws.send(json.dumps({'type':kind,'alias':alias,'subscription':alias,'uid':'123','session_id':self.sessions[alias].session_id,**values}))
def read(self):return json.loads(self.ws.recv())
def test_shared_port_two_accounts_live_delivery_and_ack(self):
for alias in ('one','two'):
self.send('subscribe',alias);self.assertEqual(self.read()['type'],'subscribed')
self.sessions['two'].publish_notices([notice('9007199254740993123')])
message=self.read();self.assertEqual(message['alias'],'two')
delivery=message['deliveries'][0]
self.assertEqual(delivery['notice']['event_key'],'9007199254740993123')
self.send('ack','two',delivery_ids=[delivery['delivery_id']])
self.send('unsubscribe','one');self.send('subscribe','one');self.assertEqual(self.read()['type'],'subscribed')
self.assertEqual(self.sessions['two'].pending(),[])
def test_unconfirmed_batch_is_replayed_after_reconnect(self):
self.send('subscribe');self.read();self.sessions['one'].publish_notices([notice('12')]);first=self.read()
self.ws.close()
self.ws=websocket.create_connection('ws://127.0.0.1:%s/v1/channel'%self.server.server_port,
header=['Authorization: Bearer test'],timeout=2)
self.send('subscribe');self.read();second=self.read()
self.assertEqual(first['deliveries'],second['deliveries'])
def test_plain_http_request_requires_upgrade(self):
request=urllib.request.Request('http://127.0.0.1:%s/v1/channel'%self.server.server_port,headers={'Authorization':'Bearer test'})
with self.assertRaises(urllib.error.HTTPError) as failure:
urllib.request.urlopen(request,timeout=2)
self.assertEqual(failure.exception.code,400)
def test_busy_browser_operation_does_not_delay_channel_subscription(self):
lock = threading.Lock();lock.acquire()
self.server.gateway._alias_lock = lambda alias:lock
try:
self.send('subscribe');self.assertEqual(self.read()['type'],'subscribed')
finally:
lock.release()
def test_waiting_channel_does_not_hold_alias_lock(self):
lock = threading.Lock()
self.server.gateway._alias_lock = lambda alias:lock
self.send('subscribe');self.read()
self.assertTrue(lock.acquire(timeout=.1));lock.release()
def test_one_stopped_account_does_not_disconnect_another(self):
self.send('subscribe','one');self.read();self.send('subscribe','two');self.read()
self.sessions['one'].stop()
self.assertEqual(self.read()['type'],'error')
self.sessions['two'].publish_notices([notice('22')])
self.assertEqual(self.read()['alias'],'two')
def test_old_session_is_rejected_after_same_generation_restart(self):
self.send('subscribe',session_id='previous-session')
self.assertEqual(self.read()['type'],'error')
def test_uid_mismatch_is_rejected_without_disconnect_for_other_accounts(self):
self.send('subscribe','two');self.assertEqual(self.read()['type'],'subscribed')
self.send('subscribe',uid='999')
self.assertEqual(self.read()['type'],'error')
self.sessions['two'].publish_notices([notice('23')])
self.assertEqual(self.read()['alias'],'two')
def test_invalid_ack_is_reported_not_silently_removed(self):
self.send('subscribe');self.read();self.sessions['one'].publish_notices([notice('1')]);self.read()
self.send('ack',delivery_ids=['not-delivered']);self.assertEqual(self.read()['type'],'error')
self.assertEqual(len(self.sessions['one'].pending()),1)
if __name__=='__main__':unittest.main()