96 lines
5.1 KiB
Python
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()
|