2024-05-08 00:36:34 +00:00
|
|
|
"""Unit tests for atproto_firehose.py."""
|
2024-05-08 17:39:03 +00:00
|
|
|
from unittest import skip
|
2024-05-08 00:36:34 +00:00
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
import arroba.util
|
2024-05-08 17:39:03 +00:00
|
|
|
from carbox import read_car, write_car
|
2024-05-08 00:36:34 +00:00
|
|
|
from carbox.car import Block
|
|
|
|
import dag_cbor
|
|
|
|
from google.cloud.tasks_v2.types import Task
|
|
|
|
from granary.tests.test_bluesky import (
|
|
|
|
ACTOR_PROFILE_BSKY,
|
2024-05-08 17:39:03 +00:00
|
|
|
LIKE_BSKY,
|
2024-05-08 00:36:34 +00:00
|
|
|
POST_BSKY,
|
|
|
|
REPLY_BSKY,
|
|
|
|
REPOST_BSKY,
|
|
|
|
)
|
|
|
|
from multiformats import CID
|
|
|
|
from oauth_dropins.webutil.appengine_config import tasks_client
|
|
|
|
from oauth_dropins.webutil import util
|
|
|
|
import simple_websocket
|
|
|
|
|
|
|
|
from atproto import ATProto
|
2024-05-08 17:39:03 +00:00
|
|
|
from atproto_firehose import new_commits, subscribe
|
2024-05-08 00:36:34 +00:00
|
|
|
import common
|
|
|
|
from models import Object, PROTOCOLS, Target
|
|
|
|
import protocol
|
|
|
|
from .testutil import ExplicitEnableFake, Fake, TestCase
|
|
|
|
from .test_atproto import DID_DOC
|
|
|
|
|
2024-05-08 17:39:03 +00:00
|
|
|
DID_DOC_ALICE = {
|
|
|
|
**DID_DOC,
|
|
|
|
'id': 'did:plc:alice',
|
|
|
|
}
|
|
|
|
|
2024-05-08 00:36:34 +00:00
|
|
|
|
|
|
|
class FakeWebsocketClient:
|
|
|
|
"""Fake of :class:`simple_websocket.Client`."""
|
|
|
|
|
|
|
|
def __init__(self, url):
|
|
|
|
FakeWebsocketClient.url = url
|
|
|
|
|
|
|
|
def send(self, msg):
|
|
|
|
self.sent.append(json.loads(msg))
|
|
|
|
|
|
|
|
def receive(self):
|
|
|
|
if not self.to_receive:
|
|
|
|
raise simple_websocket.ConnectionClosed(message='foo')
|
|
|
|
|
|
|
|
header, payload = self.to_receive.pop(0)
|
|
|
|
return dag_cbor.encode(header) + dag_cbor.encode(payload)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def setup_receive(cls, path, record, action='create', repo='did:plc:user'):
|
|
|
|
cid = CID.decode('bafkreicqpqncshdd27sgztqgzocd3zhhqnnsv6slvzhs5uz6f57cq6lmtq')
|
|
|
|
block = Block(decoded=record)
|
|
|
|
block_bytes = write_car([cid], [block])
|
|
|
|
|
|
|
|
cls.to_receive = [({
|
|
|
|
'op': 1,
|
|
|
|
't': '#commit',
|
|
|
|
}, {
|
|
|
|
'blocks': block_bytes,
|
|
|
|
'commit': cid,
|
|
|
|
'ops': [{
|
|
|
|
'action': action,
|
|
|
|
'cid': block.cid,
|
|
|
|
'path': path,
|
|
|
|
}],
|
|
|
|
'prev': None,
|
|
|
|
'rebase': False,
|
|
|
|
'repo': repo,
|
|
|
|
'rev': 'abc',
|
|
|
|
'seq': 123,
|
|
|
|
'since': 'def',
|
|
|
|
'time': util.now().isoformat(),
|
|
|
|
'tooBig': False,
|
|
|
|
})]
|
|
|
|
|
|
|
|
|
2024-05-08 17:39:03 +00:00
|
|
|
class ATProtoFirehoseSubscribeTest(TestCase):
|
2024-05-08 00:36:34 +00:00
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
|
|
|
|
simple_websocket.Client = FakeWebsocketClient
|
|
|
|
FakeWebsocketClient.sent = []
|
|
|
|
FakeWebsocketClient.to_receive = []
|
|
|
|
|
2024-05-08 17:39:03 +00:00
|
|
|
def test_error(self):
|
2024-05-08 00:36:34 +00:00
|
|
|
FakeWebsocketClient.to_receive = [(
|
|
|
|
{'op': -1},
|
|
|
|
{'error': 'ConsumerTooSlow', 'message': 'ketchup!'},
|
|
|
|
)]
|
|
|
|
|
|
|
|
subscribe()
|
2024-05-08 17:39:03 +00:00
|
|
|
self.assertTrue(new_commits.empty())
|
2024-05-08 00:36:34 +00:00
|
|
|
|
2024-05-08 17:39:03 +00:00
|
|
|
def test_info(self):
|
2024-05-08 00:36:34 +00:00
|
|
|
FakeWebsocketClient.to_receive = [(
|
|
|
|
{'op': 1, 't': '#info'},
|
|
|
|
{'name': 'OutdatedCursor'},
|
|
|
|
)]
|
|
|
|
|
|
|
|
subscribe()
|
2024-05-08 17:39:03 +00:00
|
|
|
self.assertTrue(new_commits.empty())
|
2024-05-08 00:36:34 +00:00
|
|
|
|
2024-05-08 17:39:03 +00:00
|
|
|
def test_non_commit(self):
|
2024-05-08 00:36:34 +00:00
|
|
|
FakeWebsocketClient.to_receive = [(
|
|
|
|
{'op': 1, 't': '#handle'},
|
|
|
|
{'seq': '123', 'did': 'did:abc', 'handle': 'hi.com'},
|
|
|
|
)]
|
|
|
|
|
|
|
|
subscribe()
|
2024-05-08 17:39:03 +00:00
|
|
|
self.assertTrue(new_commits.empty())
|
2024-05-08 00:36:34 +00:00
|
|
|
|
2024-05-08 17:39:03 +00:00
|
|
|
def test_not_for_us(self):
|
|
|
|
self.store_object(id='did:plc:alice', raw=DID_DOC_ALICE)
|
2024-05-08 00:36:34 +00:00
|
|
|
self.make_user('did:plc:alice', cls=ATProto, enabled_protocols=['eefake'])
|
|
|
|
self.make_user('eefake:bob', cls=ExplicitEnableFake,
|
|
|
|
enabled_protocols=['atproto'])
|
|
|
|
self.assertEqual(2, Object.query().count())
|
|
|
|
|
|
|
|
FakeWebsocketClient.setup_receive('app.bsky.feed.like/abc123', POST_BSKY)
|
|
|
|
|
|
|
|
subscribe()
|
2024-05-08 17:39:03 +00:00
|
|
|
self.assertTrue(new_commits.empty())
|
|
|
|
|
|
|
|
def test_post_by_atproto_user(self):
|
|
|
|
self.store_object(id='did:plc:user', raw=DID_DOC)
|
|
|
|
user = self.make_user('did:plc:user', cls=ATProto,
|
|
|
|
enabled_protocols=['eefake'],
|
|
|
|
obj_bsky=ACTOR_PROFILE_BSKY)
|
2024-05-08 00:36:34 +00:00
|
|
|
self.assertEqual(2, Object.query().count())
|
2024-05-08 17:39:03 +00:00
|
|
|
|
|
|
|
FakeWebsocketClient.setup_receive('app.bsky.feed.post/abc123', POST_BSKY)
|
|
|
|
|
|
|
|
subscribe()
|
|
|
|
self.assertEqual(('create', POST_BSKY), new_commits.get())
|
|
|
|
self.assertTrue(new_commits.empty())
|
|
|
|
|
|
|
|
def test_like_of_atproto_user(self):
|
|
|
|
alice = self.make_user('eefake:alice', cls=ExplicitEnableFake,
|
|
|
|
copies=[Target(protocol='atproto', uri='did:alice')])
|
|
|
|
|
|
|
|
FakeWebsocketClient.setup_receive('app.bsky.feed.like/abc123', LIKE_BSKY)
|
|
|
|
|
|
|
|
subscribe()
|
|
|
|
self.assertEqual(('create', LIKE_BSKY), new_commits.get())
|
|
|
|
self.assertTrue(new_commits.empty())
|
|
|
|
|
|
|
|
|
|
|
|
class ATProtoFirehoseHandleTest(TestCase):
|
|
|
|
@skip
|
|
|
|
def test_handle(self):
|
|
|
|
at_uri = 'at://did:plc:user/app.bsky.feed.like/abc123'
|
|
|
|
user_key = ATProto(id='did:plc:user').key
|
|
|
|
obj = self.assert_object(at_uri, bsky=LIKE_BSKY, status='new',
|
|
|
|
source_protocol='bsky', users=[user_key],
|
|
|
|
notify=alice.key)
|
|
|
|
self.assert_task(mock_create_task, 'receive', '/queue/receive',
|
|
|
|
obj=obj.key.urlsafe(), authed_as='did:plc:user')
|