import asyncio import logging import os from binascii import hexlify from lbry.testcase import CommandTestCase from lbry.blob_exchange.downloader import BlobDownloader class FileCommands(CommandTestCase): VERBOSITY = logging.WARN async def test_file_management(self): await self.stream_create('foo', '0.01') await self.stream_create('foo2', '0.01') file1, file2 = self.sout(self.daemon.jsonrpc_file_list('claim_name')) self.assertEqual(file1['claim_name'], 'foo') self.assertEqual(file2['claim_name'], 'foo2') await self.daemon.jsonrpc_file_delete(claim_name='foo') self.assertEqual(len(self.daemon.jsonrpc_file_list()), 1) await self.daemon.jsonrpc_file_delete(claim_name='foo2') self.assertEqual(len(self.daemon.jsonrpc_file_list()), 0) await self.daemon.jsonrpc_get('lbry://foo') self.assertEqual(len(self.daemon.jsonrpc_file_list()), 1) async def test_announces(self): # announces on publish self.assertEqual(await self.daemon.storage.get_blobs_to_announce(), []) await self.stream_create('foo', '0.01') stream = self.daemon.jsonrpc_file_list()[0] self.assertSetEqual( set(await self.daemon.storage.get_blobs_to_announce()), {stream.sd_hash, stream.descriptor.blobs[0].blob_hash} ) self.assertTrue(await self.daemon.jsonrpc_file_delete(delete_all=True)) # announces on download self.assertEqual(await self.daemon.storage.get_blobs_to_announce(), []) stream = await self.daemon.jsonrpc_get('foo') self.assertSetEqual( set(await self.daemon.storage.get_blobs_to_announce()), {stream.sd_hash, stream.descriptor.blobs[0].blob_hash} ) async def test_publish_with_illegal_chars(self): # Stream a file with file name containing invalid chars prefix = '?an|t:z< m<' suffix = '.ext.' san_prefix = 'antz m' san_suffix = '.ext' tx = await self.stream_create('foo', '0.01', prefix=prefix, suffix=suffix) stream = self.daemon.jsonrpc_file_list()[0] # Assert that file list and source contains the local unsanitized name, but suggested name is sanitized source_file_name = tx['outputs'][0]['value']['source']['name'] file_list_name = stream.file_name suggested_file_name = stream.descriptor.suggested_file_name self.assertTrue(source_file_name.startswith(prefix)) self.assertTrue(source_file_name.endswith(suffix)) self.assertEqual(file_list_name, source_file_name) self.assertTrue(suggested_file_name.startswith(san_prefix)) self.assertTrue(suggested_file_name.endswith(san_suffix)) # Delete the file, re-download and assert that the file name is sanitized self.assertTrue(await self.daemon.jsonrpc_file_delete(claim_name='foo')) self.assertEqual(len(self.daemon.jsonrpc_file_list()), 0) full_path = (await self.daemon.jsonrpc_get('lbry://foo', save_file=True)).full_path file_name = os.path.basename(full_path) self.assertTrue(os.path.isfile(full_path)) self.assertTrue(file_name.startswith(san_prefix)) self.assertTrue(file_name.endswith(san_suffix)) # Assert that the downloaded file name is not sanitized when user provides custom file name self.assertTrue(await self.daemon.jsonrpc_file_delete(claim_name='foo')) file_name = 'my use the claim address to pay tx = await self.stream_create( 'nofeeaddress', '0.01', data=b'free stuff?', ) await self.__raw_value_update_no_fee_address( tx, fee_amount='2.0', fee_currency='LBC', claim_address=target_address ) await self.daemon.jsonrpc_file_delete(claim_name='nofeeaddress') self.assertEqual(len(self.daemon.jsonrpc_file_list()), 0) response = await self.out(self.daemon.jsonrpc_get('lbry://nofeeaddress')) self.assertIsNone(self.daemon.jsonrpc_file_list()[0].stream_claim_info.claim.stream.fee.address) self.assertIsNotNone(response['content_fee']) self.assertEqual(len(self.daemon.jsonrpc_file_list()), 1) self.assertEqual(response['content_fee']['outputs'][0]['amount'], '2.0') self.assertEqual(response['content_fee']['outputs'][0]['address'], target_address) async def test_null_max_key_fee(self): target_address = await self.blockchain.get_raw_change_address() self.daemon.conf.max_key_fee = None await self.stream_create( 'somename', '0.5', data=b'Yes, please', fee_currency='LBC', fee_amount='1.0', fee_address=target_address ) self.assertTrue(await self.daemon.jsonrpc_file_delete(claim_name='somename')) # Assert the fee and bid are subtracted await self.assertBalance(self.account, '9.483893') response = await self.daemon.jsonrpc_get('lbry://somename') await self.ledger.wait(response.content_fee) await self.assertBalance(self.account, '8.483769') # Assert the file downloads await asyncio.wait_for(self.wait_files_to_complete(), timeout=1) self.assertEqual(len(self.daemon.jsonrpc_file_list()), 1) # Assert the transaction is recorded to the blockchain starting_balance = await self.blockchain.get_balance() await self.generate(1) block_reward_and_claim_fee = 2.0 self.assertEqual( await self.blockchain.get_balance(), starting_balance + block_reward_and_claim_fee ) async def test_null_fee(self): target_address = await self.blockchain.get_raw_change_address() tx = await self.stream_create( 'nullfee', '0.01', data=b'no pay me, no', fee_currency='LBC', fee_address=target_address, fee_amount='1.0' ) await self.__raw_value_update_no_fee_amount(tx, target_address) await self.daemon.jsonrpc_file_delete(claim_name='nullfee') response = await self.daemon.jsonrpc_get('lbry://nullfee') self.assertEqual(len(self.daemon.jsonrpc_file_list()), 1) self.assertIsNone(response.content_fee) self.assertTrue(response.stream_claim_info.claim.stream.has_fee) self.assertDictEqual( response.stream_claim_info.claim.stream.to_dict()['fee'], {'currency': 'LBC', 'address': target_address} ) await self.daemon.jsonrpc_file_delete(claim_name='nullfee') async def __raw_value_update_no_fee_address(self, tx, claim_address, **kwargs): tx = await self.daemon.jsonrpc_stream_update( self.get_claim_id(tx), preview=True, claim_address=claim_address, **kwargs ) tx.outputs[0].claim.stream.fee.address_bytes = b'' tx.outputs[0].script.generate() await tx.sign([self.account]) await self.broadcast(tx) await self.confirm_tx(tx.id) async def __raw_value_update_no_fee_amount(self, tx, claim_address): tx = await self.daemon.jsonrpc_stream_update( self.get_claim_id(tx), preview=True, fee_currency='LBC', fee_amount='1.0', fee_address=claim_address, claim_address=claim_address ) tx.outputs[0].claim.stream.fee.message.ClearField('amount') tx.outputs[0].script.generate() await tx.sign([self.account]) await self.broadcast(tx) await self.confirm_tx(tx.id)