catch invalid None value for all cases when creating/updating claims

This commit is contained in:
Lex Berezhny 2019-12-13 10:44:41 -05:00
parent 2ae068c2d2
commit 8a49ad4586
4 changed files with 38 additions and 23 deletions

View file

@ -33,6 +33,7 @@ Code | Name | Message
105 | CommandPermanentlyUnavailable | Command '{command}' is permanently unavailable. -- such as when required component was intentionally configured not to start. 105 | CommandPermanentlyUnavailable | Command '{command}' is permanently unavailable. -- such as when required component was intentionally configured not to start.
**11x** | InputValue(ValueError) | Invalid argument value provided to command. **11x** | InputValue(ValueError) | Invalid argument value provided to command.
111 | GenericInputValue | The value '{value}' for argument '{argument}' is not valid. 111 | GenericInputValue | The value '{value}' for argument '{argument}' is not valid.
112 | InputValueIsNone | None or null is not valid value for argument '{argument}'.
**2xx** | Configuration | Configuration errors. **2xx** | Configuration | Configuration errors.
201 | ConfigWrite | Cannot write configuration file '{path}'. -- When writing the default config fails on startup, such as due to permission issues. 201 | ConfigWrite | Cannot write configuration file '{path}'. -- When writing the default config fails on startup, such as due to permission issues.
202 | ConfigRead | Cannot find provided configuration file '{path}'. -- Can't open the config file user provided via command line args. 202 | ConfigRead | Cannot find provided configuration file '{path}'. -- Can't open the config file user provided via command line args.

View file

@ -61,6 +61,12 @@ class GenericInputValueError(InputValueError):
super().__init__(f"The value '{value}' for argument '{argument}' is not valid.") super().__init__(f"The value '{value}' for argument '{argument}' is not valid.")
class InputValueIsNoneError(InputValueError):
def __init__(self, argument):
super().__init__(f"None or null is not valid value for argument '{argument}'.")
class ConfigurationError(BaseError): class ConfigurationError(BaseError):
""" """
Configuration errors. Configuration errors.

View file

@ -16,6 +16,7 @@ from lbry.schema.attrs import (
LanguageList, LocationList, ClaimList, ClaimReference, TagList LanguageList, LocationList, ClaimList, ClaimReference, TagList
) )
from lbry.schema.types.v2.claim_pb2 import Claim as ClaimMessage from lbry.schema.types.v2.claim_pb2 import Claim as ClaimMessage
from lbry.error import InputValueIsNoneError
hachoir_log.use_print = False hachoir_log.use_print = False
@ -119,17 +120,19 @@ class BaseClaim:
claim['locations'] = [l.to_dict() for l in self.locations] claim['locations'] = [l.to_dict() for l in self.locations]
return claim return claim
def none_check(self, kwargs):
for key, value in kwargs.items():
if value is None:
raise InputValueIsNoneError(key)
def update(self, **kwargs): def update(self, **kwargs):
self.none_check(kwargs)
for key in list(kwargs): for key in list(kwargs):
for field in self.object_fields: for field in self.object_fields:
if key.startswith(f'{field}_'): if key.startswith(f'{field}_'):
attr = getattr(self, field) attr = getattr(self, field)
setattr(attr, key[len(f'{field}_'):], kwargs.pop(key))
attr_value = kwargs.pop(key)
if attr_value is None:
raise ValueError(f"Error updating claim - Null value provided for attribute {field}")
setattr(attr, key[len(f'{field}_'):], attr_value)
continue continue
for l in self.repeat_fields: for l in self.repeat_fields:
@ -212,6 +215,8 @@ class Stream(BaseClaim):
return claim return claim
def update(self, file_path=None, height=None, width=None, duration=None, **kwargs): def update(self, file_path=None, height=None, width=None, duration=None, **kwargs):
self.none_check(kwargs)
if kwargs.pop('clear_fee', False): if kwargs.pop('clear_fee', False):
self.message.ClearField('fee') self.message.ClearField('fee')
else: else:

View file

@ -1,8 +1,8 @@
from unittest import TestCase from unittest import TestCase
from unittest.mock import patch
from decimal import Decimal from decimal import Decimal
from lbry.schema.claim import Claim, Stream, Collection, BaseClaim from lbry.schema.claim import Claim, Stream, Collection
from lbry.error import InputValueIsNoneError
class TestClaimContainerAwareness(TestCase): class TestClaimContainerAwareness(TestCase):
@ -198,19 +198,22 @@ class TestLocations(TestCase):
self.assertEqual(stream.locations[0].country, 'UA') self.assertEqual(stream.locations[0].country, 'UA')
class TestBaseClaimUpdates(TestCase): class TestStreamUpdating(TestCase):
@patch('lbry.schema.claim.Claim')
def test_claim_update_url_ok(self, MockClaim):
# test if an attribute is provided correctly
base_claim = BaseClaim(MockClaim)
base_claim.update(thumbnail_url="somescheme:some/path")
self.assertEqual(base_claim.thumbnail.url, "somescheme:some/path")
@patch('lbry.schema.claim.Claim')
def test_claim_update_url_error(self, MockClaim):
# test if an attribute is null
base_claim = BaseClaim(MockClaim)
with self.assertRaisesRegex(ValueError, "Error updating claim - Null value provided for attribute thumbnail"):
base_claim.update(thumbnail_url=None)
def test_stream_update(self):
stream = Stream()
# each of these values is set differently inside of .update()
stream.update(
title="foo",
thumbnail_url="somescheme:some/path",
file_name="file-name"
)
self.assertEqual(stream.title, "foo")
self.assertEqual(stream.thumbnail.url, "somescheme:some/path")
self.assertEqual(stream.source.name, "file-name")
with self.assertRaises(InputValueIsNoneError):
stream.update(title=None)
with self.assertRaises(InputValueIsNoneError):
stream.update(file_name=None)
with self.assertRaises(InputValueIsNoneError):
stream.update(thumbnail_url=None)