diff --git a/lbrynet/conf.py b/lbrynet/conf.py index f037694a8..dfa273063 100644 --- a/lbrynet/conf.py +++ b/lbrynet/conf.py @@ -534,7 +534,7 @@ class Config(CLIConfig): ('lbrynet4.lbry.com', 4444) # ASIA ]) - comment_server = String("Updated Comment Server version.", "https://comments.lbry.com/api") + comment_server = String("Comment server API URL", "https://comments.lbry.com/api") # blockchain blockchain_name = String("Blockchain name - lbrycrd_main, lbrycrd_regtest, or lbrycrd_testnet", 'lbrycrd_main') diff --git a/lbrynet/extras/daemon/Daemon.py b/lbrynet/extras/daemon/Daemon.py index 08b3a8b02..ed3887695 100644 --- a/lbrynet/extras/daemon/Daemon.py +++ b/lbrynet/extras/daemon/Daemon.py @@ -2278,7 +2278,7 @@ class Daemon(metaclass=JSONRPCServerType): --duration= : (int) audio/video duration in seconds, automatically calculated --channel_id= : (str) claim id of the publisher channel --channel_name= : (str) name of publisher channel - --channel_account_id=: (str) one or more account ids for accounts to look in + --channel_account_id=: (str) one or more account ids for accounts to look in for channel certificates, defaults to all accounts. --account_id= : (str) account to use for funding the transaction --claim_address=: (str) address where the claim is sent to, if not specified @@ -2391,7 +2391,7 @@ class Daemon(metaclass=JSONRPCServerType): --duration= : (int) audio/video duration in seconds, automatically calculated --channel_id= : (str) claim id of the publisher channel --channel_name= : (str) name of the publisher channel - --channel_account_id=: (str) one or more account ids for accounts to look in + --channel_account_id=: (str) one or more account ids for accounts to look in for channel certificates, defaults to all accounts. --account_id= : (str) account to use for funding the transaction --claim_address=: (str) address where the claim is sent to, if not specified @@ -2541,7 +2541,7 @@ class Daemon(metaclass=JSONRPCServerType): --channel_id= : (str) claim id of the publisher channel --channel_name= : (str) name of the publisher channel --clear_channel : (bool) remove channel signature - --channel_account_id=: (str) one or more account ids for accounts to look in + --channel_account_id=: (str) one or more account ids for accounts to look in for channel certificates, defaults to all accounts. --account_id= : (str) account to use for funding the transaction --claim_address=: (str) address where the claim is sent to, if not specified @@ -3382,25 +3382,27 @@ class Daemon(metaclass=JSONRPCServerType): top_level=not include_replies ) - async def jsonrpc_comment_create(self, claim_id: str, comment: str, parent_id: str = None, - channel_name: str = None, channel_id: str = None) -> dict: + async def jsonrpc_comment_create( + self, claim_id: str, comment: str, parent_id: str = None, + channel_account_id=None, channel_name: str = None, channel_id: str = None) -> dict: """ Create and associate a comment with a claim using your channel identity. Usage: comment_create ( | --comment=) ( | --claim_id=) - [--channel_id=] - [--channel_name=] [--parent_id=] + [--channel_id=] [--channel_name=] + [--channel_account_id=...] Options: --comment= : (str) Comment to be made, should be at most 2000 characters. --claim_id= : (str) The ID of the claim on which the comment should be made on --parent_id= : (str) The ID of a comment to make a response to --channel_id= : (str) The ID of the channel you want to post under - --channel_name= : (str) The channel you want to post as, prepend with a '@' - + --channel_name=: (str) The channel you want to post as, prepend with a '@' + --channel_account_id=: (str) one or more account ids for accounts to look in + for channel certificates, defaults to all accounts. Returns: (dict) Comment object if successfully made, (None) otherwise @@ -3415,34 +3417,23 @@ class Daemon(metaclass=JSONRPCServerType): "timestamp": (int) The time at which comment was entered into the server at, in nanoseconds. } """ - if bool(channel_name) ^ bool(channel_id): - try: - channel_list = await self.jsonrpc_channel_list() - if channel_name: - channel_name = channel_name.lower() - channel: Output = [chan for chan in channel_list if chan.normalized_name == channel_name].pop() - channel_id = channel.claim_id - else: - channel: Output = [chan for chan in channel_list if chan.claim_id == channel_id].pop() - channel_name = channel.normalized_name - except IndexError: - raise ValueError('You must enter a valid channel_%s' % ('id' if channel_id else 'name')) - signature = None - if channel_id and channel_name: - signature = sign_comment( - channel_name=channel_name, - channel_id=channel_id, - comment=comment, - salt=time.time_ns() - ) comment = { 'comment': comment, 'claim_id': claim_id, 'parent_id': parent_id, - 'channel_id': channel_id, - 'channel_name': channel_name, - 'signature': signature } + channel = await self.get_channel_or_none(channel_account_id, channel_id, channel_name, for_signing=True) + if channel: + comment.update({ + 'channel_id': channel.claim_id, + 'channel_name': channel.claim_name, + 'signature': sign_comment( + channel_name=channel_name, + channel_id=channel_id, + comment=comment, + salt=time.time_ns() + ) + }) return await jsonrpc_post(self.conf.comment_server, 'create_comment', **comment) def valid_address_or_error(self, address): diff --git a/lbrynet/testcase.py b/lbrynet/testcase.py index b3b76462b..17f8e7e23 100644 --- a/lbrynet/testcase.py +++ b/lbrynet/testcase.py @@ -58,7 +58,6 @@ class ExchangeRateManagerComponent(Component): class CommandTestCase(IntegrationTestCase): - timeout = 180 LEDGER = lbrynet.wallet MANAGER = LbryWalletManager VERBOSITY = logging.WARN diff --git a/tests/integration/test_comment_commands.py b/tests/integration/test_comment_commands.py index 177175d05..f65d0d0e0 100644 --- a/tests/integration/test_comment_commands.py +++ b/tests/integration/test_comment_commands.py @@ -1,61 +1,16 @@ -import logging -import time - import asyncio from aiohttp import web from lbrynet.testcase import CommandTestCase -import lbrynet.schema -lbrynet.schema.BLOCKCHAIN_NAME = 'lbrycrd_regtest' - -COMMENT_IDS = [ - "b7de681c412e315bb1a9ada6f485a2e0399400db", - "0f7e1514f55c7fefba1e714386e05b3d705f6d29", - "8ae19f686c39f402c80dabf25df23cf72fe426af", - "a11ad59b54bb937ca1a88329f253b17196bd4dc3", - "7ee87b3249fa47b296c8347cd63bba679ef629eb", - "0100e3367f68284f4970736c9351ad90c37dade5", - "974a5bfcce6bc72605688ba6e2efd34aa934b1dc", - "97ea100a52aa46ae9f2a4356169307a2505e8d47", - "2b4d193371c8f0ed45c830cb1ba3188b90bf08f1", - "db335dc3183ca3552b6ef4a7bce36f26ed37b7eb" -] - -CLAIM_IDS = [ - "f6068bdc8cb66fe7eb6c3cf4cf98da93a697df47", - "44a8c10e36ed8b60da8d5fe590cba61544fb7179", - "a7d8a1fc90ab806c98743a7f9ca7480e2cebe2a0", - "81a8cc2fa41eea0ae9d65ab0f8a0440605a23f1b", - "49117e9a7bb2aab01356e1160871aad5edb09ed5", - "2b928261918b1f7c65973c8fee9e20d4a1f1b2a4", - "f9d6eb75d1592a967b1c405208593d30b46446c9", - "cc70bd497eb1305096fa4e28275645f47c5d809d", - "2e520f60bd8f79f309d68b291fe574531a7d6656", - "16b0248c103fb7b3497bd58543f6c5dd6d47d5f2" -] - -CHANNEL_IDS = [ - "7b65a9886869a367371ec621abe5bac4e5dd27b9", - "c3bbde23a8b31dc05490cede3a381080b024f878", - "c544579ca13ce5d97e9301789620547323da15eb", - "428e1c075b27bbce1380c16ecb5f0d228318315e", - "1558b39438f573a47a5e0fcd78ad24d0eb358be0", - "ac66521e1757d320568a52ab8b01029bd169b1a0", - "aa89729a08050694ffb62e725356bbaa26481193", - "23181733dc3b836e4d38e8cc21d79378b855cf36", - "60efc8ced56a6a02c2d5371310f0130c541a9ded", - "af1c95f2026d4a254512dd6e6a792a9d92b9fd21" -] - class FakedCommentServer: + ERRORS = { 'INVALID_PARAMS': {'code': -32602, 'message': 'Invalid parameters'}, 'INTERNAL': {'code': -32603, 'message': 'An internal error'}, 'UNKNOWN': {'code': -1, 'message': 'An unknown or very miscellaneous error'}, 'INVALID_METHOD': {'code': -32604, 'message': 'The Requested method does not exist'} - } def __init__(self, port=2903): @@ -64,24 +19,17 @@ class FakedCommentServer: self.app.add_routes([web.post('/api', self.api)]) self.runner = None self.server = None + self.comments = [] + self.comment_id = 0 - def get_comment(self, **kwargs) -> dict: - return { - 'comment_id': 'asbdsdasd', - 'parent_id': 'asdsfsfsf', - 'comment': 'asdsdadsdas', - 'timestamp': time.time_ns(), - 'channel_id': 'asdsdsdasdad', - 'channel_name': 'asdsasasfaf', - 'channel_uri': 'asdsdasda', - 'signature': 'aasdasdasda', - } - - def create_comment(self, comment, claim_id, **kwargs): - return self.get_comment(**kwargs) + def create_comment(self, **comment): + self.comment_id += 1 + comment['comment_id'] = self.comment_id + self.comments.append(comment) + return comment def get_claim_comments(self, page=1, page_size=50, **kwargs): - return [self.get_comment(**kwargs) for i in range(page_size)] + return self.comments[:page_size] methods = { 'get_claim_comments': get_claim_comments, @@ -98,24 +46,16 @@ class FakedCommentServer: response['error'] = self.ERRORS['INVALID_METHOD'] return response - async def _start(self): + async def start(self): self.runner = web.AppRunner(self.app) await self.runner.setup() self.server = web.TCPSite(self.runner, 'localhost', self.port) await self.server.start() - async def _stop(self): + async def stop(self): + await self.runner.shutdown() await self.runner.cleanup() - async def run(self, max_timeout=3600): - try: - await self._start() - await asyncio.sleep(max_timeout) - except asyncio.CancelledError: - pass - finally: - await self._stop() - async def api(self, request): body = await request.json() if type(body) is list or type(body) is dict: @@ -130,76 +70,36 @@ class FakedCommentServer: class CommentCommands(CommandTestCase): - VERBOSITY = logging.WARN - async def asyncSetUp(self): await super().asyncSetUp() self.daemon.conf.comment_server = 'http://localhost:2903/api' - self.server = FakedCommentServer(2903) - self.server_task = asyncio.create_task(self.server.run(self.timeout)) - - async def asyncTearDown(self): - await super().asyncTearDown() - self.server_task.cancel() - if not self.server_task.cancelled(): - await self.server_task + self.comment_server = FakedCommentServer(2903) + await self.comment_server.start() + self.addCleanup(self.comment_server.stop) async def test_comment_create(self): + channel = (await self.channel_create('@JimmyBuffett'))['outputs'][0] + stream = (await self.stream_create())['outputs'][0] + + self.assertEqual(0, len(await self.daemon.jsonrpc_comment_list(stream['claim_id']))) comment = await self.daemon.jsonrpc_comment_create( - claim_id=CLAIM_IDS[0], - channel_name='@JimmyBuffett', - channel_id=CHANNEL_IDS[0], + claim_id=stream['claim_id'], + channel_id=channel['claim_id'], comment="It's 5 O'Clock Somewhere" ) - self.assertIsNotNone(comment) - self.assertNotIn('error', comment) - self.assertIn('comment', comment, msg=f"Response {comment} doesn't contain message") - self.assertIn('channel_name', comment) + comments = await self.daemon.jsonrpc_comment_list(stream['claim_id']) + self.assertEqual(1, len(comments)) + self.assertEqual(comment['comment_id'], comments[0]['comment_id']) + self.assertEqual(stream['claim_id'], comments[0]['claim_id']) - async def test_comment_create_reply(self): - reply = await self.daemon.jsonrpc_comment_create( - claim_id=CLAIM_IDS[0], - channel_name='@JimmyBuffett', - channel_id=CHANNEL_IDS[0], + channel2 = (await self.channel_create('@BuffettJimmy'))['outputs'][0] + await self.daemon.jsonrpc_comment_create( + claim_id=stream['claim_id'], + channel_name=channel2['name'], comment='Let\'s all go to Margaritaville', - parent_id=COMMENT_IDS[0] + parent_id=comments[0]['comment_id'] ) - self.assertIsNotNone(reply) - self.assertNotIn('error', reply) - self.assertIn('comment_id', reply) - self.assertIsNotNone(reply['parent_id']) - - async def test_comment_list_root_level(self): - comments = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[0]) - self.assertIsNotNone(comments) - self.assertIs(type(comments), list) - comments = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[1], page_size=50) - self.assertIsNotNone(comments) - self.assertLessEqual(len(comments), 50) - self.assertGreaterEqual(len(comments), 0) - - async def test_comment_list_replies(self): - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[0], parent_id=23) - self.assertIsInstance(replies, list) - self.assertGreater(len(replies), 0) - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[2], parent_id=COMMENT_IDS[3], page_size=50) - self.assertEqual(len(replies), 50) - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[3], parent_id=COMMENT_IDS[5], - page_size=23, page=5) - self.assertEqual(len(replies), 23) - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[5], parent_id=COMMENT_IDS[1], - page_size=60, page=2) - self.assertEqual(len(replies), 60) - - async def test_comment_list_flatness_flatness_LA(self): - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[2], parent_id=23, include_replies=True) - self.assertGreater(len(replies), 0) - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[6], parent_id=25, - page_size=50, include_replies=True) - self.assertGreaterEqual(len(replies), 0) - self.assertLessEqual(len(replies), 50) - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[7], parent_id=67, page_size=23, page=5) - self.assertGreaterEqual(len(replies), 0) - self.assertLessEqual(len(replies), 23) - replies = await self.daemon.jsonrpc_comment_list(CLAIM_IDS[9], parent_id=79, page=2, include_replies=True) - self.assertGreaterEqual(len(replies), 15) + comments = await self.daemon.jsonrpc_comment_list(stream['claim_id']) + self.assertEqual(2, len(comments)) + self.assertEqual(comments[1]['channel_id'], channel2['claim_id']) + self.assertEqual(comments[0]['comment_id'], comments[1]['parent_id'])