working integration tests

This commit is contained in:
Lex Berezhny 2018-10-16 15:04:20 -04:00
parent 1ca82b9d52
commit 5eac4247e1
6 changed files with 122 additions and 103 deletions

View file

@ -53,17 +53,16 @@ class ComponentManager:
for component_class in self.component_classes.values(): for component_class in self.component_classes.values():
self.components.add(component_class(self)) self.components.add(component_class(self))
@defer.inlineCallbacks
def evaluate_condition(self, condition_name): def evaluate_condition(self, condition_name):
if condition_name not in RegisteredConditions.conditions: if condition_name not in RegisteredConditions.conditions:
raise NameError(condition_name) raise NameError(condition_name)
condition = RegisteredConditions.conditions[condition_name] condition = RegisteredConditions.conditions[condition_name]
try: try:
component = self.get_component(condition.component) component = self.get_component(condition.component)
result = yield defer.maybeDeferred(condition.evaluate, component) result = condition.evaluate(component)
except Exception as err: except Exception as err:
result = False result = False
defer.returnValue((result, "" if result else condition.message)) return result, "" if result else condition.message
def sort_components(self, reverse=False): def sort_components(self, reverse=False):
""" """

View file

@ -83,8 +83,7 @@ DIRECTION_DESCENDING = 'desc'
DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING DIRECTIONS = DIRECTION_ASCENDING, DIRECTION_DESCENDING
@defer.inlineCallbacks async def maybe_paginate(get_records: Callable, get_record_count: Callable,
def maybe_paginate(get_records: Callable, get_record_count: Callable,
page: Optional[int], page_size: Optional[int], **constraints): page: Optional[int], page_size: Optional[int], **constraints):
if None not in (page, page_size): if None not in (page, page_size):
constraints.update({ constraints.update({
@ -92,11 +91,11 @@ def maybe_paginate(get_records: Callable, get_record_count: Callable,
"limit": page_size "limit": page_size
}) })
return { return {
"items": (yield get_records(**constraints)), "items": await get_records(**constraints),
"total_pages": int(((yield get_record_count(**constraints)) + (page_size-1)) / page_size), "total_pages": int(((await get_record_count(**constraints)) + (page_size-1)) / page_size),
"page": page, "page_size": page_size "page": page, "page_size": page_size
} }
return (yield get_records(**constraints)) return await get_records(**constraints)
class IterableContainer: class IterableContainer:
@ -200,9 +199,7 @@ class WalletIsUnlocked(RequiredCondition):
@staticmethod @staticmethod
def evaluate(component): def evaluate(component):
d = component.check_locked() return not component.check_locked()
d.addCallback(lambda r: not r)
return d
class Daemon(AuthJSONRPCServer): class Daemon(AuthJSONRPCServer):
@ -403,8 +400,7 @@ class Daemon(AuthJSONRPCServer):
del self.streams[sd_hash] del self.streams[sd_hash]
defer.returnValue(result) defer.returnValue(result)
@defer.inlineCallbacks async def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate=None,
def _publish_stream(self, name, bid, claim_dict, file_path=None, certificate=None,
claim_address=None, change_address=None): claim_address=None, change_address=None):
publisher = Publisher( publisher = Publisher(
self.blob_manager, self.payment_rate_manager, self.storage, self.blob_manager, self.payment_rate_manager, self.storage,
@ -412,11 +408,11 @@ class Daemon(AuthJSONRPCServer):
) )
parse_lbry_uri(name) parse_lbry_uri(name)
if not file_path: if not file_path:
stream_hash = yield self.storage.get_stream_hash_for_sd_hash( stream_hash = await d2f(self.storage.get_stream_hash_for_sd_hash(
claim_dict['stream']['source']['source']) claim_dict['stream']['source']['source']))
tx = yield publisher.publish_stream(name, bid, claim_dict, stream_hash, claim_address) tx = await publisher.publish_stream(name, bid, claim_dict, stream_hash, claim_address)
else: else:
tx = yield publisher.create_and_publish_stream(name, bid, claim_dict, file_path, claim_address) tx = await publisher.create_and_publish_stream(name, bid, claim_dict, file_path, claim_address)
if conf.settings['reflect_uploads']: if conf.settings['reflect_uploads']:
d = reupload.reflect_file(publisher.lbry_file) d = reupload.reflect_file(publisher.lbry_file)
d.addCallbacks(lambda _: log.info("Reflected new publication to lbry://%s", name), d.addCallbacks(lambda _: log.info("Reflected new publication to lbry://%s", name),
@ -425,13 +421,13 @@ class Daemon(AuthJSONRPCServer):
nout = 0 nout = 0
txo = tx.outputs[nout] txo = tx.outputs[nout]
log.info("Success! Published to lbry://%s txid: %s nout: %d", name, tx.id, nout) log.info("Success! Published to lbry://%s txid: %s nout: %d", name, tx.id, nout)
defer.returnValue({ return {
"success": True, "success": True,
"tx": tx, "tx": tx,
"claim_id": txo.claim_id, "claim_id": txo.claim_id,
"claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash']), "claim_address": self.ledger.hash160_to_address(txo.script.values['pubkey_hash']),
"output": tx.outputs[nout] "output": tx.outputs[nout]
}) }
def _get_or_download_sd_blob(self, blob, sd_hash): def _get_or_download_sd_blob(self, blob, sd_hash):
if blob: if blob:
@ -1043,8 +1039,7 @@ class Daemon(AuthJSONRPCServer):
pass pass
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
@defer.inlineCallbacks async def jsonrpc_wallet_send(self, amount, address=None, claim_id=None, account_id=None):
def jsonrpc_wallet_send(self, amount, address=None, claim_id=None, account_id=None):
""" """
Send credits. If given an address, send credits to it. If given a claim id, send a tip Send credits. If given an address, send credits to it. If given a claim id, send a tip
to the owner of a claim specified by uri. A tip is a claim support where the recipient to the owner of a claim specified by uri. A tip is a claim support where the recipient
@ -1102,11 +1097,11 @@ class Daemon(AuthJSONRPCServer):
if reserved_points is None: if reserved_points is None:
raise InsufficientFundsError() raise InsufficientFundsError()
account = self.get_account_or_default(account_id) account = self.get_account_or_default(account_id)
result = yield self.wallet_manager.send_points_to_address(reserved_points, amount, account) result = await self.wallet_manager.send_points_to_address(reserved_points, amount, account)
self.analytics_manager.send_credits_sent() self.analytics_manager.send_credits_sent()
else: else:
log.info("This command is deprecated for sending tips, please use the newer claim_tip command") log.info("This command is deprecated for sending tips, please use the newer claim_tip command")
result = yield self.jsonrpc_claim_tip(claim_id=claim_id, amount=amount, account_id=account_id) result = await self.jsonrpc_claim_tip(claim_id=claim_id, amount=amount, account_id=account_id)
return result return result
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
@ -1181,8 +1176,7 @@ class Daemon(AuthJSONRPCServer):
confirmations=confirmations, show_seed=show_seed) confirmations=confirmations, show_seed=show_seed)
@requires("wallet") @requires("wallet")
@defer.inlineCallbacks async def jsonrpc_account_balance(self, account_id=None, confirmations=0):
def jsonrpc_account_balance(self, account_id=None, confirmations=0):
""" """
Return the balance of an account Return the balance of an account
@ -1199,12 +1193,11 @@ class Daemon(AuthJSONRPCServer):
(decimal) amount of lbry credits in wallet (decimal) amount of lbry credits in wallet
""" """
account = self.get_account_or_default(account_id) account = self.get_account_or_default(account_id)
dewies = yield account.get_balance(confirmations=confirmations) dewies = await account.get_balance(confirmations=confirmations)
return dewies_to_lbc(dewies) return dewies_to_lbc(dewies)
@requires("wallet") @requires("wallet")
@defer.inlineCallbacks async def jsonrpc_account_add(
def jsonrpc_account_add(
self, account_name, single_key=False, seed=None, private_key=None, public_key=None): self, account_name, single_key=False, seed=None, private_key=None, public_key=None):
""" """
Add a previously created account from a seed, private key or public key (read-only). Add a previously created account from a seed, private key or public key (read-only).
@ -1239,7 +1232,7 @@ class Daemon(AuthJSONRPCServer):
) )
if self.ledger.network.is_connected: if self.ledger.network.is_connected:
yield self.ledger.update_account(account) await self.ledger.update_account(account)
self.default_wallet.save() self.default_wallet.save()
@ -1251,8 +1244,7 @@ class Daemon(AuthJSONRPCServer):
return result return result
@requires("wallet") @requires("wallet")
@defer.inlineCallbacks async def jsonrpc_account_create(self, account_name, single_key=False):
def jsonrpc_account_create(self, account_name, single_key=False):
""" """
Create a new account. Specify --single_key if you want to use Create a new account. Specify --single_key if you want to use
the same address for all transactions (not recommended). the same address for all transactions (not recommended).
@ -1275,7 +1267,7 @@ class Daemon(AuthJSONRPCServer):
) )
if self.ledger.network.is_connected: if self.ledger.network.is_connected:
yield self.ledger.update_account(account) await self.ledger.update_account(account)
self.default_wallet.save() self.default_wallet.save()
@ -1710,8 +1702,7 @@ class Daemon(AuthJSONRPCServer):
defer.returnValue(response) defer.returnValue(response)
@requires(WALLET_COMPONENT) @requires(WALLET_COMPONENT)
@defer.inlineCallbacks async def jsonrpc_resolve(self, force=False, uri=None, uris=None):
def jsonrpc_resolve(self, force=False, uri=None, uris=[]):
""" """
Resolve given LBRY URIs Resolve given LBRY URIs
@ -1779,7 +1770,7 @@ class Daemon(AuthJSONRPCServer):
} }
""" """
uris = tuple(uris) uris = tuple(uris or [])
if uri is not None: if uri is not None:
uris += (uri,) uris += (uri,)
@ -1793,12 +1784,10 @@ class Daemon(AuthJSONRPCServer):
except URIParseError: except URIParseError:
results[u] = {"error": "%s is not a valid uri" % u} results[u] = {"error": "%s is not a valid uri" % u}
resolved = yield self.wallet_manager.resolve(*valid_uris, check_cache=not force) resolved = await self.wallet_manager.resolve(*valid_uris, check_cache=not force)
for resolved_uri in resolved: for resolved_uri in resolved:
results[resolved_uri] = resolved[resolved_uri] results[resolved_uri] = resolved[resolved_uri]
response = yield self._render_response(results) return results
defer.returnValue(response)
@requires(STREAM_IDENTIFIER_COMPONENT, WALLET_COMPONENT, EXCHANGE_RATE_MANAGER_COMPONENT, BLOB_COMPONENT, @requires(STREAM_IDENTIFIER_COMPONENT, WALLET_COMPONENT, EXCHANGE_RATE_MANAGER_COMPONENT, BLOB_COMPONENT,
DHT_COMPONENT, RATE_LIMITER_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT, DHT_COMPONENT, RATE_LIMITER_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT,
@ -2010,8 +1999,7 @@ class Daemon(AuthJSONRPCServer):
return self.get_est_cost(uri, size) return self.get_est_cost(uri, size)
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
@defer.inlineCallbacks async def jsonrpc_channel_new(self, channel_name, amount):
def jsonrpc_channel_new(self, channel_name, amount):
""" """
Generate a publisher key and create a new '@' prefixed certificate claim Generate a publisher key and create a new '@' prefixed certificate claim
@ -2046,7 +2034,7 @@ class Daemon(AuthJSONRPCServer):
if amount <= 0: if amount <= 0:
raise Exception("Invalid amount") raise Exception("Invalid amount")
tx = yield self.wallet_manager.claim_new_channel(channel_name, amount) tx = await self.wallet_manager.claim_new_channel(channel_name, amount)
self.default_wallet.save() self.default_wallet.save()
self.analytics_manager.send_new_channel() self.analytics_manager.send_new_channel()
nout = 0 nout = 0
@ -2125,8 +2113,7 @@ class Daemon(AuthJSONRPCServer):
@requires(WALLET_COMPONENT, FILE_MANAGER_COMPONENT, BLOB_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT, @requires(WALLET_COMPONENT, FILE_MANAGER_COMPONENT, BLOB_COMPONENT, PAYMENT_RATE_COMPONENT, DATABASE_COMPONENT,
conditions=[WALLET_IS_UNLOCKED]) conditions=[WALLET_IS_UNLOCKED])
@defer.inlineCallbacks async def jsonrpc_publish(self, name, bid, metadata=None, file_path=None, fee=None, title=None,
def jsonrpc_publish(self, name, bid, metadata=None, file_path=None, fee=None, title=None,
description=None, author=None, language=None, license=None, description=None, author=None, language=None, license=None,
license_url=None, thumbnail=None, preview=None, nsfw=None, sources=None, license_url=None, thumbnail=None, preview=None, nsfw=None, sources=None,
channel_name=None, channel_id=None, channel_name=None, channel_id=None,
@ -2221,7 +2208,7 @@ class Daemon(AuthJSONRPCServer):
# raises an error if the address is invalid # raises an error if the address is invalid
decode_address(address) decode_address(address)
available = yield self.default_account.get_balance() available = await self.default_account.get_balance()
if amount >= available: if amount >= available:
# TODO: add check for existing claim balance # TODO: add check for existing claim balance
#balance = yield self.wallet.get_max_usable_balance_for_claim(name) #balance = yield self.wallet.get_max_usable_balance_for_claim(name)
@ -2273,7 +2260,7 @@ class Daemon(AuthJSONRPCServer):
log.warning("Stripping empty fee from published metadata") log.warning("Stripping empty fee from published metadata")
del metadata['fee'] del metadata['fee']
elif 'address' not in metadata['fee']: elif 'address' not in metadata['fee']:
address = yield self.default_account.receiving.get_or_create_usable_address() address = await self.default_account.receiving.get_or_create_usable_address()
metadata['fee']['address'] = address metadata['fee']['address'] = address
if 'fee' in metadata and 'version' not in metadata['fee']: if 'fee' in metadata and 'version' not in metadata['fee']:
metadata['fee']['version'] = '_0_0_1' metadata['fee']['version'] = '_0_0_1'
@ -2316,7 +2303,7 @@ class Daemon(AuthJSONRPCServer):
certificate = None certificate = None
if channel_id or channel_name: if channel_id or channel_name:
certificate = yield self.get_channel_or_error(channel_id, channel_name) certificate = await self.get_channel_or_error(channel_id, channel_name)
log.info("Publish: %s", { log.info("Publish: %s", {
'name': name, 'name': name,
@ -2329,13 +2316,13 @@ class Daemon(AuthJSONRPCServer):
'channel_name': channel_name 'channel_name': channel_name
}) })
result = yield self._publish_stream(name, amount, claim_dict, file_path, certificate, return await self._publish_stream(
claim_address, change_address) name, amount, claim_dict, file_path, certificate,
return result claim_address, change_address
)
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
@defer.inlineCallbacks async def jsonrpc_claim_abandon(self, claim_id=None, txid=None, nout=None, account_id=None):
def jsonrpc_claim_abandon(self, claim_id=None, txid=None, nout=None, account_id=None):
""" """
Abandon a name and reclaim credits from the claim Abandon a name and reclaim credits from the claim
@ -2366,16 +2353,12 @@ class Daemon(AuthJSONRPCServer):
if nout is None and txid is not None: if nout is None and txid is not None:
raise Exception('Must specify nout') raise Exception('Must specify nout')
tx = yield self.wallet_manager.abandon_claim(claim_id, txid, nout, account) tx = await self.wallet_manager.abandon_claim(claim_id, txid, nout, account)
self.analytics_manager.send_claim_action('abandon') self.analytics_manager.send_claim_action('abandon')
defer.returnValue({ return {"success": True, "tx": tx}
"success": True,
"tx": tx,
})
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
@defer.inlineCallbacks async def jsonrpc_claim_new_support(self, name, claim_id, amount, account_id=None):
def jsonrpc_claim_new_support(self, name, claim_id, amount, account_id=None):
""" """
Support a name claim Support a name claim
@ -2403,13 +2386,12 @@ class Daemon(AuthJSONRPCServer):
""" """
account = self.get_account_or_default(account_id) account = self.get_account_or_default(account_id)
amount = self.get_dewies_or_error("amount", amount) amount = self.get_dewies_or_error("amount", amount)
result = yield self.wallet_manager.support_claim(name, claim_id, amount, account) result = await self.wallet_manager.support_claim(name, claim_id, amount, account)
self.analytics_manager.send_claim_action('new_support') self.analytics_manager.send_claim_action('new_support')
return result return result
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED]) @requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
@defer.inlineCallbacks async def jsonrpc_claim_tip(self, claim_id, amount, account_id=None):
def jsonrpc_claim_tip(self, claim_id, amount, account_id=None):
""" """
Tip the owner of the claim Tip the owner of the claim
@ -2437,7 +2419,7 @@ class Daemon(AuthJSONRPCServer):
account = self.get_account_or_default(account_id) account = self.get_account_or_default(account_id)
amount = self.get_dewies_or_error("amount", amount) amount = self.get_dewies_or_error("amount", amount)
validate_claim_id(claim_id) validate_claim_id(claim_id)
result = yield self.wallet_manager.tip_claim(amount, claim_id, account) result = await self.wallet_manager.tip_claim(amount, claim_id, account)
self.analytics_manager.send_claim_action('new_support') self.analytics_manager.send_claim_action('new_support')
return result return result
@ -3294,16 +3276,15 @@ class Daemon(AuthJSONRPCServer):
response['head_blob_availability'].get('is_available') response['head_blob_availability'].get('is_available')
defer.returnValue(response) defer.returnValue(response)
@defer.inlineCallbacks async def get_channel_or_error(self, channel_id: str = None, channel_name: str = None):
def get_channel_or_error(self, channel_id: str = None, channel_name: str = None):
if channel_id is not None: if channel_id is not None:
certificates = yield self.wallet_manager.get_certificates( certificates = await self.wallet_manager.get_certificates(
private_key_accounts=[self.default_account], claim_id=channel_id) private_key_accounts=[self.default_account], claim_id=channel_id)
if not certificates: if not certificates:
raise ValueError("Couldn't find channel with claim_id '{}'." .format(channel_id)) raise ValueError("Couldn't find channel with claim_id '{}'." .format(channel_id))
return certificates[0] return certificates[0]
if channel_name is not None: if channel_name is not None:
certificates = yield self.wallet_manager.get_certificates( certificates = await self.wallet_manager.get_certificates(
private_key_accounts=[self.default_account], claim_name=channel_name) private_key_accounts=[self.default_account], claim_name=channel_name)
if not certificates: if not certificates:
raise ValueError("Couldn't find channel with name '{}'.".format(channel_name)) raise ValueError("Couldn't find channel with name '{}'.".format(channel_name))

View file

@ -1,14 +1,17 @@
import asyncio
import logging import logging
import mimetypes import mimetypes
import os import os
from twisted.internet import defer
from lbrynet.file_manager.EncryptedFileCreator import create_lbry_file from lbrynet.file_manager.EncryptedFileCreator import create_lbry_file
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def d2f(d):
return d.asFuture(asyncio.get_event_loop())
class Publisher: class Publisher:
def __init__(self, blob_manager, payment_rate_manager, storage, lbry_file_manager, wallet, certificate): def __init__(self, blob_manager, payment_rate_manager, storage, lbry_file_manager, wallet, certificate):
self.blob_manager = blob_manager self.blob_manager = blob_manager
@ -19,8 +22,7 @@ class Publisher:
self.certificate = certificate self.certificate = certificate
self.lbry_file = None self.lbry_file = None
@defer.inlineCallbacks async def create_and_publish_stream(self, name, bid, claim_dict, file_path, holding_address=None):
def create_and_publish_stream(self, name, bid, claim_dict, file_path, holding_address=None):
"""Create lbry file and make claim""" """Create lbry file and make claim"""
log.info('Starting publish for %s', name) log.info('Starting publish for %s', name)
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
@ -30,10 +32,10 @@ class Publisher:
file_name = os.path.basename(file_path) file_name = os.path.basename(file_path)
with open(file_path, 'rb') as read_handle: with open(file_path, 'rb') as read_handle:
self.lbry_file = yield create_lbry_file( self.lbry_file = await d2f(create_lbry_file(
self.blob_manager, self.storage, self.payment_rate_manager, self.lbry_file_manager, file_name, self.blob_manager, self.storage, self.payment_rate_manager, self.lbry_file_manager, file_name,
read_handle read_handle
) ))
if 'source' not in claim_dict['stream']: if 'source' not in claim_dict['stream']:
claim_dict['stream']['source'] = {} claim_dict['stream']['source'] = {}
@ -41,37 +43,36 @@ class Publisher:
claim_dict['stream']['source']['sourceType'] = 'lbry_sd_hash' claim_dict['stream']['source']['sourceType'] = 'lbry_sd_hash'
claim_dict['stream']['source']['contentType'] = get_content_type(file_path) claim_dict['stream']['source']['contentType'] = get_content_type(file_path)
claim_dict['stream']['source']['version'] = "_0_0_1" # need current version here claim_dict['stream']['source']['version'] = "_0_0_1" # need current version here
tx = yield self.wallet.claim_name( tx = await self.wallet.claim_name(
name, bid, claim_dict, self.certificate, holding_address name, bid, claim_dict, self.certificate, holding_address
) )
# check if we have a file already for this claim (if this is a publish update with a new stream) # check if we have a file already for this claim (if this is a publish update with a new stream)
old_stream_hashes = yield self.storage.get_old_stream_hashes_for_claim_id( old_stream_hashes = await d2f(self.storage.get_old_stream_hashes_for_claim_id(
tx.outputs[0].claim_id, self.lbry_file.stream_hash tx.outputs[0].claim_id, self.lbry_file.stream_hash
) ))
if old_stream_hashes: if old_stream_hashes:
for lbry_file in filter(lambda l: l.stream_hash in old_stream_hashes, for lbry_file in filter(lambda l: l.stream_hash in old_stream_hashes,
list(self.lbry_file_manager.lbry_files)): list(self.lbry_file_manager.lbry_files)):
yield self.lbry_file_manager.delete_lbry_file(lbry_file, delete_file=False) await d2f(self.lbry_file_manager.delete_lbry_file(lbry_file, delete_file=False))
log.info("Removed old stream for claim update: %s", lbry_file.stream_hash) log.info("Removed old stream for claim update: %s", lbry_file.stream_hash)
yield self.storage.save_content_claim( await d2f(self.storage.save_content_claim(
self.lbry_file.stream_hash, tx.outputs[0].id self.lbry_file.stream_hash, tx.outputs[0].id
) ))
defer.returnValue(tx) return tx
@defer.inlineCallbacks async def publish_stream(self, name, bid, claim_dict, stream_hash, holding_address=None):
def publish_stream(self, name, bid, claim_dict, stream_hash, holding_address=None):
"""Make a claim without creating a lbry file""" """Make a claim without creating a lbry file"""
tx = yield self.wallet.claim_name( tx = await self.wallet.claim_name(
name, bid, claim_dict, self.certificate, holding_address name, bid, claim_dict, self.certificate, holding_address
) )
if stream_hash: # the stream_hash returned from the db will be None if this isn't a stream we have if stream_hash: # the stream_hash returned from the db will be None if this isn't a stream we have
yield self.storage.save_content_claim( await d2f(self.storage.save_content_claim(
stream_hash, tx.outputs[0].id stream_hash, tx.outputs[0].id
) ))
self.lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0] self.lbry_file = [f for f in self.lbry_file_manager.lbry_files if f.stream_hash == stream_hash][0]
defer.returnValue(tx) return tx
def get_content_type(filename): def get_content_type(filename):

View file

@ -1,3 +1,4 @@
import asyncio
import logging import logging
from six.moves.urllib import parse as urlparse from six.moves.urllib import parse as urlparse
import json import json
@ -7,6 +8,7 @@ import signal
from functools import wraps from functools import wraps
from twisted.web import server from twisted.web import server
from twisted.internet import defer from twisted.internet import defer
from twisted.internet.defer import Deferred
from twisted.python.failure import Failure from twisted.python.failure import Failure
from twisted.internet.error import ConnectionDone, ConnectionLost from twisted.internet.error import ConnectionDone, ConnectionLost
from txjsonrpc import jsonrpclib from txjsonrpc import jsonrpclib
@ -141,19 +143,17 @@ class AuthorizedBase(metaclass=JSONRPCServerType):
condition_names = conditions.get("conditions", []) condition_names = conditions.get("conditions", [])
def _wrap(fn): def _wrap(fn):
@defer.inlineCallbacks
@wraps(fn) @wraps(fn)
def _inner(*args, **kwargs): def _inner(*args, **kwargs):
component_manager = args[0].component_manager component_manager = args[0].component_manager
for condition_name in condition_names: for condition_name in condition_names:
condition_result, err_msg = yield component_manager.evaluate_condition(condition_name) condition_result, err_msg = component_manager.evaluate_condition(condition_name)
if not condition_result: if not condition_result:
raise ComponentStartConditionNotMet(err_msg) raise ComponentStartConditionNotMet(err_msg)
if not component_manager.all_components_running(*components): if not component_manager.all_components_running(*components):
raise ComponentsNotStarted("the following required components have not yet started: " raise ComponentsNotStarted("the following required components have not yet started: "
"%s" % json.dumps(components)) "%s" % json.dumps(components))
result = yield fn(*args, **kwargs) return fn(*args, **kwargs)
defer.returnValue(result)
return _inner return _inner
return _wrap return _wrap
@ -446,7 +446,18 @@ class AuthJSONRPCServer(AuthorizedBase):
) )
return server.NOT_DONE_YET return server.NOT_DONE_YET
d = defer.maybeDeferred(fn, self, *_args, **_kwargs) try:
result = fn(self, *_args, **_kwargs)
if isinstance(result, Deferred):
d = result
elif isinstance(result, Failure):
d = defer.fail(result)
elif asyncio.iscoroutine(result):
d = Deferred.fromFuture(asyncio.ensure_future(result))
else:
d = defer.succeed(result)
except:
d = Failure(captureVars=Deferred.debug)
# finished_deferred will callback when the request is finished # finished_deferred will callback when the request is finished
# and errback if something went wrong. If the errback is # and errback if something went wrong. If the errback is

View file

@ -1,5 +1,6 @@
import os import os
import json import json
import asyncio
import logging import logging
from binascii import unhexlify from binascii import unhexlify
@ -265,7 +266,8 @@ class LbryWalletManager(BaseWalletManager):
ledger: MainNetLedger = self.default_account.ledger ledger: MainNetLedger = self.default_account.ledger
results = await ledger.resolve(page, page_size, *uris) results = await ledger.resolve(page, page_size, *uris)
await self.old_db.save_claims_for_resolve( await self.old_db.save_claims_for_resolve(
(value for value in results.values() if 'error' not in value)) (value for value in results.values() if 'error' not in value)
).asFuture(asyncio.get_event_loop())
return results return results
def get_claims_for_name(self, name: str): def get_claims_for_name(self, name: str):
@ -362,7 +364,7 @@ class LbryWalletManager(BaseWalletManager):
await account.ledger.broadcast(tx) await account.ledger.broadcast(tx)
await self.old_db.save_claims([self._old_get_temp_claim_info( await self.old_db.save_claims([self._old_get_temp_claim_info(
tx, tx.outputs[0], claim_address, claim_dict, name, amount tx, tx.outputs[0], claim_address, claim_dict, name, amount
)]) )]).asFuture(asyncio.get_event_loop())
# TODO: release reserved tx outputs in case anything fails by this point # TODO: release reserved tx outputs in case anything fails by this point
return tx return tx

View file

@ -4,7 +4,11 @@ import tempfile
import logging import logging
from types import SimpleNamespace from types import SimpleNamespace
from orchstr8.testcase import IntegrationTestCase from twisted.trial import unittest
from twisted.internet import utils, defer
from twisted.internet.utils import runWithWarningsSuppressed as originalRunWith
from orchstr8.testcase import IntegrationTestCase as BaseIntegrationTestCase
import lbryschema import lbryschema
lbryschema.BLOCKCHAIN_NAME = 'lbrycrd_regtest' lbryschema.BLOCKCHAIN_NAME = 'lbrycrd_regtest'
@ -86,13 +90,34 @@ class FakeAnalytics:
pass pass
class IntegrationTestCase(unittest.TestCase, BaseIntegrationTestCase):
async def setUp(self):
await self.asyncSetUp()
async def tearDown(self):
await self.asyncTearDown()
def run_with_async_support(suppress, f, *a, **kw):
if asyncio.iscoroutinefunction(f):
def test_method(*args, **kwargs):
return defer.Deferred.fromFuture(asyncio.ensure_future(f(*args, **kwargs)))
else:
test_method = f
return originalRunWith(suppress, test_method, *a, **kw)
utils.runWithWarningsSuppressed = run_with_async_support
class CommandTestCase(IntegrationTestCase): class CommandTestCase(IntegrationTestCase):
timeout = 180 timeout = 180
WALLET_MANAGER = LbryWalletManager WALLET_MANAGER = LbryWalletManager
async def asyncSetUp(self): async def setUp(self):
await super().asyncSetUp() await super().setUp()
if self.VERBOSE: if self.VERBOSE:
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
@ -139,8 +164,8 @@ class CommandTestCase(IntegrationTestCase):
self.daemon.wallet_manager = self.wallet_component.wallet_manager self.daemon.wallet_manager = self.wallet_component.wallet_manager
self.manager.old_db = self.daemon.storage self.manager.old_db = self.daemon.storage
async def asyncTearDown(self): async def tearDown(self):
await super().asyncTearDown() await super().tearDown()
self.wallet_component._running = False self.wallet_component._running = False
await d2f(self.daemon._shutdown()) await d2f(self.daemon._shutdown())
@ -300,7 +325,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
file.write(b'Totally un-cliched ending') file.write(b'Totally un-cliched ending')
file.write(b'**Audience Gasps**') file.write(b'**Audience Gasps**')
file.flush() file.flush()
claim3 = yield self.out(self.daemon.jsonrpc_publish( claim3 = await self.out(self.daemon.jsonrpc_publish(
'fresh-start', '1.0', file_path=file.name, channel_name='@spam' 'fresh-start', '1.0', file_path=file.name, channel_name='@spam'
)) ))
self.assertTrue(claim3['success']) self.assertTrue(claim3['success'])
@ -360,7 +385,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
file.write(b'I know right? Totally a hit song') file.write(b'I know right? Totally a hit song')
file.write(b'That\'s what goes around for songs these days anyways') file.write(b'That\'s what goes around for songs these days anyways')
file.flush() file.flush()
claim4 = yield self.out(self.daemon.jsonrpc_publish( claim4 = await self.out(self.daemon.jsonrpc_publish(
'hit-song', '1.0', file_path=file.name, channel_id=channel['claim_id'] 'hit-song', '1.0', file_path=file.name, channel_id=channel['claim_id']
)) ))
self.assertTrue(claim4['success']) self.assertTrue(claim4['success'])
@ -384,7 +409,7 @@ class EpicAdventuresOfChris45(CommandTestCase):
class AccountManagement(CommandTestCase): class AccountManagement(CommandTestCase):
VERBOSE = True VERBOSE = False
async def test_performing_account_management_commands(self): async def test_performing_account_management_commands(self):
# check initial account # check initial account
@ -393,7 +418,7 @@ class AccountManagement(CommandTestCase):
# change account name and gap # change account name and gap
account_id = response['lbc_regtest'][0]['id'] account_id = response['lbc_regtest'][0]['id']
await self.daemon.jsonrpc_account_set( self.daemon.jsonrpc_account_set(
account_id=account_id, new_name='test account', account_id=account_id, new_name='test account',
receiving_gap=95, receiving_max_uses=96, receiving_gap=95, receiving_max_uses=96,
change_gap=97, change_max_uses=98 change_gap=97, change_max_uses=98
@ -424,7 +449,7 @@ class AccountManagement(CommandTestCase):
account_seed = response['lbc_regtest'][1]['seed'] account_seed = response['lbc_regtest'][1]['seed']
# remove account # remove account
await self.daemon.jsonrpc_account_remove(response['lbc_regtest'][1]['id']) self.daemon.jsonrpc_account_remove(response['lbc_regtest'][1]['id'])
response = await self.daemon.jsonrpc_account_list() response = await self.daemon.jsonrpc_account_list()
self.assertEqual(len(response['lbc_regtest']), 1) self.assertEqual(len(response['lbc_regtest']), 1)