def test_apprise_config_tagging(tmpdir): """ API: AppriseConfig tagging """ # temporary file to work with t = tmpdir.mkdir("tagging").join("apprise") buf = "gnome://" t.write(buf) # Create ourselves a config object ac = AppriseConfig() # Add an item associated with tag a assert ac.add(configs=str(t), asset=AppriseAsset(), tag='a') is True # Add an item associated with tag b assert ac.add(configs=str(t), asset=AppriseAsset(), tag='b') is True # Add an item associated with tag a or b assert ac.add(configs=str(t), asset=AppriseAsset(), tag='a,b') is True # Now filter: a: assert len(ac.servers(tag='a')) == 2 # Now filter: a or b: assert len(ac.servers(tag='a,b')) == 3 # Now filter: a and b assert len(ac.servers(tag=[('a', 'b')])) == 1 # all matches everything assert len(ac.servers(tag='all')) == 3
def test_config_base_config_parse_yaml_list(): """ API: ConfigBase.config_parse_yaml list parsing """ # general reference used below asset = AppriseAsset() # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" # no lists... just no urls: [milk, pumpkin pie, eggs, juice] # Including by list is okay include: [file:///absolute/path/, relative/path, http://test.com] """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were 3 include entries assert len(config) == 3 assert 'file:///absolute/path/' in config assert 'relative/path' in config assert 'http://test.com' in config
def test_apprise_add_config(): """ API AppriseConfig.add_config() """ content = """ # A comment line over top of a URL mailto://usera:[email protected] # A line with mulitiple tag assignments to it taga,tagb=gnome:// # Event if there is accidental leading spaces, this configuation # is accepting of htat and will not exclude them tagc=kde:// # A very poorly structured url sns://:@/ # Just 1 token provided causes exception sns://T1JJ3T3L2/ """ # Create ourselves a config object ac = AppriseConfig() assert ac.add_config(content=content) # One configuration file should have been found assert len(ac) == 1 # Object can be directly checked as a boolean; response is True # when there is at least one entry assert ac # We should be able to read our 3 servers from that assert len(ac.servers()) == 3 # Get our URL back assert isinstance(ac[0].url(), six.string_types) # Test invalid content assert ac.add_config(content=object()) is False assert ac.add_config(content=42) is False assert ac.add_config(content=None) is False # Still only one server loaded assert len(ac) == 1 # Test having a pre-defined asset object and tag created assert ac.add_config( content=content, asset=AppriseAsset(), tag='a') is True # Now there are 2 servers loaded assert len(ac) == 2 # and 6 urls.. (as we've doubled up) assert len(ac.servers()) == 6
def test_invalid_apprise_config(tmpdir): """ Parse invalid configuration includes """ class BadConfig(ConfigBase): # always allow incusion allow_cross_includes = ConfigIncludeMode.ALWAYS def __init__(self, **kwargs): super(BadConfig, self).__init__(**kwargs) # We intentionally fail whenever we're initialized raise TypeError() @staticmethod def parse_url(url, *args, **kwargs): # always parseable return ConfigBase.parse_url(url, verify_host=False) # Store our bad configuration in our schema map CONFIG_SCHEMA_MAP['bad'] = BadConfig # temporary file to work with t = tmpdir.mkdir("apprise-bad-obj").join("invalid") buf = """ # Include an invalid schema include invalid:// # An unparsable valid schema include https:// # A valid configuration that will throw an exception include bad:// # Include ourselves (So our recursive includes fails as well) include {} """.format(str(t)) t.write(buf) # Create ourselves a config object with caching disbled ac = AppriseConfig(recursion=2, insecure_includes=True, cache=False) # Nothing loaded yet assert len(ac) == 0 # Add our config assert ac.add(configs=str(t), asset=AppriseAsset()) is True # One configuration file assert len(ac) == 1 # All of the servers were invalid and would not load assert len(ac.servers()) == 0
def test_apprise_config_tagging(tmpdir): """ API: AppriseConfig tagging """ # temporary file to work with t = tmpdir.mkdir("tagging").join("apprise") buf = "gnome://" t.write(buf) # Create ourselves a config object ac = AppriseConfig() # Add an item associated with tag a assert ac.add(configs=str(t), asset=AppriseAsset(), tag='a') is True # Add an item associated with tag b assert ac.add(configs=str(t), asset=AppriseAsset(), tag='b') is True # Add an item associated with tag a or b assert ac.add(configs=str(t), asset=AppriseAsset(), tag='a,b') is True # Now filter: a: assert len(ac.servers(tag='a')) == 2 # Now filter: a or b: assert len(ac.servers(tag='a,b')) == 3 # Now filter: a and b assert len(ac.servers(tag=[('a', 'b')])) == 1 # all matches everything assert len(ac.servers(tag='all')) == 3 # Test cases using the `always` keyword # Create ourselves a config object ac = AppriseConfig() # Add an item associated with tag a assert ac.add(configs=str(t), asset=AppriseAsset(), tag='a,always') is True # Add an item associated with tag b assert ac.add(configs=str(t), asset=AppriseAsset(), tag='b') is True # Add an item associated with tag a or b assert ac.add(configs=str(t), asset=AppriseAsset(), tag='c,d') is True # Now filter: a: assert len(ac.servers(tag='a')) == 1 # Now filter: a or b: assert len(ac.servers(tag='a,b')) == 2 # Now filter: e # we'll match the `always' assert len(ac.servers(tag='e')) == 1 assert len(ac.servers(tag='e', match_always=False)) == 0 # all matches everything assert len(ac.servers(tag='all')) == 3 # Now filter: d # we'll match the `always' tag assert len(ac.servers(tag='d')) == 2 assert len(ac.servers(tag='d', match_always=False)) == 1
def test_config_base_config_parse_yaml(): """ API: ConfigBase.config_parse_yaml object """ # general reference used below asset = AppriseAsset() # Garbage Handling assert isinstance(ConfigBase.config_parse_yaml(object()), list) assert isinstance(ConfigBase.config_parse_yaml(None), list) assert isinstance(ConfigBase.config_parse_yaml(''), list) # Invalid Version result = ConfigBase.config_parse_yaml("version: 2a", asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid Syntax (throws a ScannerError) result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Missing url token result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # No urls defined result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url defined result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 # Invalid URL definition; yet the answer to life at the same time urls: 43 """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url/schema result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: - invalid:// """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url/schema result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: - invalid://: - a: b """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url/schema result = ConfigBase.config_parse_yaml(""" urls: - just some free text that isn't valid: - a garbage entry to go with it """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url/schema result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: - not even a proper url """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url/schema result = ConfigBase.config_parse_yaml(""" # no lists... just no urls: [milk, pumpkin pie, eggs, juice] """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Invalid url/schema result = ConfigBase.config_parse_yaml(""" urls: # a very invalid sns entry - sns://T1JJ3T3L2/ - sns://:@/: - invalid: test - sns://T1JJ3T3L2/: - invalid: test # some strangness - - - test """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # Valid Configuration result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 # # Define your notification urls: # urls: - pbul://o.gn5kj6nfhv736I7jC3cj3QLRiyhgl98b - mailto://test:[email protected] """, asset=asset) # We expect to parse 2 entries from the above assert isinstance(result, list) assert len(result) == 2 assert len(result[0].tags) == 0 # Valid Configuration result = ConfigBase.config_parse_yaml(""" urls: - json://localhost: - tag: my-custom-tag, my-other-tag # How to stack multiple entries: - mailto://: - user: jeff pass: 123abc from: [email protected] - user: jack pass: pass123 from: [email protected] # This is an illegal entry; the schema can not be changed schema: json # accidently left a colon at the end of the url; no problem # we'll accept it - mailto://oscar:[email protected]: # A telegram entry (returns a None in parse_url()) - tgram://invalid """, asset=asset) # We expect to parse 4 entries from the above because the tgram:// entry # would have failed to be loaded assert isinstance(result, list) assert len(result) == 4 assert len(result[0].tags) == 2 # Global Tags result = ConfigBase.config_parse_yaml(""" # Global Tags stacked as a list tag: - admin - devops urls: - json://localhost - dbus:// """, asset=asset) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 2 # all entries will have our global tags defined in them for entry in result: assert 'admin' in entry.tags assert 'devops' in entry.tags # Global Tags result = ConfigBase.config_parse_yaml(""" # Global Tags tag: admin, devops urls: # The following tags will get added to the global set - json://localhost: - tag: string-tag, my-other-tag, text # Tags can be presented in this list format too: - dbus://: - tag: - list-tag - dbus """, asset=asset) # all entries will have our global tags defined in them for entry in result: assert 'admin' in entry.tags assert 'devops' in entry.tags # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 2 # json:// has 2 globals + 3 defined assert len(result[0].tags) == 5 assert 'text' in result[0].tags # json:// has 2 globals + 2 defined assert len(result[1].tags) == 4 assert 'list-tag' in result[1].tags # An invalid set of entries result = ConfigBase.config_parse_yaml(""" urls: # The following tags will get added to the global set - json://localhost: - - - entry """, asset=asset) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 0 # An asset we'll manipulate asset = AppriseAsset() # Global Tags result = ConfigBase.config_parse_yaml(""" # Test the creation of our apprise asset object asset: app_id: AppriseTest app_desc: Apprise Test Notifications app_url: http://nuxref.com # Support setting empty values image_url_mask: image_url_logo: image_path_mask: tmp/path # invalid entry theme: - - - entry # Now for some invalid entries invalid: entry __init__: can't be over-ridden nolists: - we don't support these entries - in the apprise object urls: - json://localhost: """, asset=asset) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 1 assert asset.app_id == "AppriseTest" assert asset.app_desc == "Apprise Test Notifications" assert asset.app_url == "http://nuxref.com" # the theme was not updated and remains the same as it was assert asset.theme == AppriseAsset().theme # Empty string assignment assert isinstance(asset.image_url_mask, six.string_types) is True assert asset.image_url_mask == "" assert isinstance(asset.image_url_logo, six.string_types) is True assert asset.image_url_logo == "" # For on-lookers looking through this file; here is a perfectly formatted # YAML configuration file for your reference so you can see it without # all of the errors like the ones identified above result = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed. Thus this is a # completely optional field. It's a good idea to just add this line because it # will help with future ambiguity (if it ever occurs). version: 1 # Define an Asset object if you wish (Optional) asset: app_id: AppriseTest app_desc: Apprise Test Notifications app_url: http://nuxref.com # Optionally define some global tags to associate with ALL of your # urls below. tag: admin, devops # Define your URLs (Mandatory!) urls: # Either on-line each entry like this: - json://localhost # Or add a colon to the end of the URL where you can optionally provide # over-ride entries. One of the most likely entry to be used here # is the tag entry. This gets extended to the global tag (if defined) # above - xml://localhost: - tag: customer # The more elements you specify under a URL the more times the URL will # get replicated and used. Hence this entry actually could be considered # 2 URLs being called with just the destination email address changed: - mailto://george:[email protected]: - to: [email protected] - to: [email protected] # Again... to re-iterate, the above mailto:// would actually fire two (2) # separate emails each with a different destination address specified. # Be careful when defining your arguments and differentiating between # when to use the dash (-) and when not to. Each time you do, you will # cause another instance to be created. # Defining more then 1 element to a muti-set is easy, it looks like this: - mailto://jackson:[email protected]: - to: [email protected] tag: jeff, customer - to: [email protected] tag: chris, customer """, asset=asset) # okay, here is how we get our total based on the above (read top-down) # +1 json:// entry # +1 xml:// entry # +2 mailto:// entry to [email protected] and [email protected] # +2 mailto:// entry to [email protected] and [email protected] # = 6 assert len(result) == 6 # all six entries will have our global tags defined in them for entry in result: assert 'admin' in entry.tags assert 'devops' in entry.tags # Entries can be directly accessed as they were added # our json:// had no additional tags added; so just the global ones # So just 2; admin and devops (these were already validated above in the # for loop assert len(result[0].tags) == 2 # our xml:// object has 1 tag added (customer) assert len(result[1].tags) == 3 assert 'customer' in result[1].tags # You get the idea, here is just a direct mapping to the remaining entries # in the same order they appear above assert len(result[2].tags) == 2 assert len(result[3].tags) == 2 assert len(result[4].tags) == 4 assert 'customer' in result[4].tags assert 'jeff' in result[4].tags assert len(result[5].tags) == 4 assert 'customer' in result[5].tags assert 'chris' in result[5].tags
def test_config_base_config_parse_text(): """ API: ConfigBase.config_parse_text object """ # Garbage Handling assert isinstance(ConfigBase.config_parse_text(object()), list) assert isinstance(ConfigBase.config_parse_text(None), list) assert isinstance(ConfigBase.config_parse_text(''), list) # Valid Configuration result = ConfigBase.config_parse_text(""" # A comment line over top of a URL mailto://userb:[email protected] # A line with mulitiple tag assignments to it taga,tagb=kde:// """, asset=AppriseAsset()) # We expect to parse 2 entries from the above assert isinstance(result, list) assert len(result) == 2 assert len(result[0].tags) == 0 # Our second element will have tags associated with it assert len(result[1].tags) == 2 assert 'taga' in result[1].tags assert 'tagb' in result[1].tags # Here is a similar result set however this one has an invalid line # in it which invalidates the entire file result = ConfigBase.config_parse_text(""" # A comment line over top of a URL mailto://userc:[email protected] # A line with mulitiple tag assignments to it taga,tagb=windows:// I am an invalid line that does not follow any of the Apprise file rules! """) # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # More invalid data result = ConfigBase.config_parse_text(""" # An invalid URL invalid://user:[email protected] # A tag without a url taga= # A very poorly structured url sns://:@/ # Just 1 token provided sns://T1JJ3T3L2/ """) # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # Here is an empty file result = ConfigBase.config_parse_text('') # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0
def test_apprise_config(tmpdir): """ API: AppriseConfig basic testing """ # Create ourselves a config object ac = AppriseConfig() # There are no servers loaded assert len(ac) == 0 # Object can be directly checked as a boolean; response is False # when there are no entries loaded assert not ac # lets try anyway assert len(ac.servers()) == 0 t = tmpdir.mkdir("simple-formatting").join("apprise") t.write(""" # A comment line over top of a URL mailto://usera:[email protected] # A line with mulitiple tag assignments to it taga,tagb=gnome:// # Event if there is accidental leading spaces, this configuation # is accepting of htat and will not exclude them tagc=kde:// # A very poorly structured url sns://:@/ # Just 1 token provided causes exception sns://T1JJ3T3L2/ """) # Create ourselves a config object ac = AppriseConfig(paths=str(t)) # One configuration file should have been found assert len(ac) == 1 # Object can be directly checked as a boolean; response is True # when there is at least one entry assert ac # We should be able to read our 3 servers from that assert len(ac.servers()) == 3 # Get our URL back assert isinstance(ac[0].url(), six.string_types) # Test cases where our URL is invalid t = tmpdir.mkdir("strange-lines").join("apprise") t.write(""" # basicly this consists of defined tags and no url tag= """) # Create ourselves a config object ac = AppriseConfig(paths=str(t), asset=AppriseAsset()) # One configuration file should have been found assert len(ac) == 1 # No urls were set assert len(ac.servers()) == 0 # Create a ConfigBase object cb = ConfigBase() # Test adding of all entries assert ac.add(configs=cb, asset=AppriseAsset(), tag='test') is True # Test adding of all entries assert ac.add( configs=['file://?', ], asset=AppriseAsset(), tag='test') is False # Test the adding of garbage assert ac.add(configs=object()) is False # Try again but enforce our format ac = AppriseConfig(paths='file://{}?format=text'.format(str(t))) # One configuration file should have been found assert len(ac) == 1 # No urls were set assert len(ac.servers()) == 0 # # Test Internatialization and the handling of unicode characters # istr = """ # Iñtërnâtiônàlization Testing windows://""" if six.PY2: # decode string into unicode istr = istr.decode('utf-8') # Write our content to our file t = tmpdir.mkdir("internationalization").join("apprise") with io.open(str(t), 'wb') as f: f.write(istr.encode('latin-1')) # Create ourselves a config object ac = AppriseConfig(paths=str(t)) # One configuration file should have been found assert len(ac) == 1 # This will fail because our default encoding is utf-8; however the file # we opened was not; it was latin-1 and could not be parsed. assert len(ac.servers()) == 0 # Test iterator count = 0 for entry in ac: count += 1 assert len(ac) == count # We can fix this though; set our encoding to latin-1 ac = AppriseConfig(paths='file://{}?encoding=latin-1'.format(str(t))) # One configuration file should have been found assert len(ac) == 1 # Our URL should be found assert len(ac.servers()) == 1 # Get our URL back assert isinstance(ac[0].url(), six.string_types) # pop an entry from our list assert isinstance(ac.pop(0), ConfigBase) is True # Determine we have no more configuration entries loaded assert len(ac) == 0 # # Test buffer handling (and overflow) t = tmpdir.mkdir("buffer-handling").join("apprise") buf = "gnome://" t.write(buf) # Reset our config object ac.clear() # Create ourselves a config object ac = AppriseConfig(paths=str(t)) # update our length to be the size of our actual file ac[0].max_buffer_size = len(buf) # One configuration file should have been found assert len(ac) == 1 assert len(ac.servers()) == 1 # update our buffer size to be slightly smaller then what we allow ac[0].max_buffer_size = len(buf) - 1 # Content is automatically cached; so even though we adjusted the buffer # above, our results have been cached so we get a 1 response. assert len(ac.servers()) == 1
def test_apprise_config_with_apprise_obj(tmpdir): """ API: ConfigBase.parse_inaccessible_text_file """ # temporary file to work with t = tmpdir.mkdir("apprise-obj").join("apprise") buf = """ good://hostname localhost=good://localhost """ t.write(buf) # Define our good:// url class GoodNotification(NotifyBase): def __init__(self, **kwargs): super(GoodNotification, self).__init__( notify_format=NotifyFormat.HTML, **kwargs) def notify(self, **kwargs): # Pretend everything is okay return True def url(self): # support url() return '' # Store our good notification in our schema map NOTIFY_SCHEMA_MAP['good'] = GoodNotification # Create ourselves a config object with caching disbled ac = AppriseConfig(cache=False) # Nothing loaded yet assert len(ac) == 0 # Add an item associated with tag a assert ac.add(configs=str(t), asset=AppriseAsset(), tag='a') is True # One configuration file assert len(ac) == 1 # 2 services found in it assert len(ac.servers()) == 2 # Pop one of them (at index 0) ac.server_pop(0) # Verify that it no longer listed assert len(ac.servers()) == 1 # Test our ability to add Config objects to our apprise object a = Apprise() # Add our configuration object assert a.add(servers=ac) is True # Detect our 1 entry (originally there were 2 but we deleted one) assert len(a) == 1 # Notify our service assert a.notify(body='apprise configuration power!') is True # Add our configuration object assert a.add( servers=[AppriseConfig(str(t)), AppriseConfig(str(t))]) is True # Detect our 5 loaded entries now; 1 from first config, and another # 2x2 based on adding our list above assert len(a) == 5 # We can't add garbage assert a.add(servers=object()) is False assert a.add(servers=[object(), object()]) is False # Our length is unchanged assert len(a) == 5 # reference index 0 of our list ref = a[0] assert isinstance(ref, NotifyBase) is True # Our length is unchanged assert len(a) == 5 # pop the index ref_popped = a.pop(0) # Verify our response assert isinstance(ref_popped, NotifyBase) is True # Our length drops by 1 assert len(a) == 4 # Content popped is the same as one referenced by index # earlier assert ref == ref_popped # pop an index out of range try: a.pop(len(a)) # We'll thrown an IndexError and not make it this far assert False except IndexError: # As expected assert True # Our length remains unchanged assert len(a) == 4 # Reference content out of range try: a[len(a)] # We'll thrown an IndexError and not make it this far assert False except IndexError: # As expected assert True # reference index at the end of our list ref = a[len(a) - 1] # Verify our response assert isinstance(ref, NotifyBase) is True # Our length stays the same assert len(a) == 4 # We can pop from the back of the list without a problem too ref_popped = a.pop(len(a) - 1) # Verify our response assert isinstance(ref_popped, NotifyBase) is True # Content popped is the same as one referenced by index # earlier assert ref == ref_popped # Our length drops by 1 assert len(a) == 3 # Now we'll test adding another element to the list so that it mixes up # our response object. # Below we add 3 different types, a ConfigBase, NotifyBase, and URL assert a.add( servers=[ ConfigFile(path=(str(t))), 'good://another.host', GoodNotification(**{'host': 'nuxref.com'})]) is True # Our length increases by 4 (2 entries in the config file, + 2 others) assert len(a) == 7 # reference index at the end of our list ref = a[len(a) - 1] # Verify our response assert isinstance(ref, NotifyBase) is True # We can pop from the back of the list without a problem too ref_popped = a.pop(len(a) - 1) # Verify our response assert isinstance(ref_popped, NotifyBase) is True # Content popped is the same as one referenced by index # earlier assert ref == ref_popped # Our length drops by 1 assert len(a) == 6 # pop our list while len(a) > 0: assert isinstance(a.pop(len(a) - 1), NotifyBase) is True
def test_config_base_config_parse_yaml(): """ API: ConfigBase.config_parse_yaml object """ # general reference used below asset = AppriseAsset() # Garbage Handling for garbage in (object(), None, '', 42): # A response is always correctly returned result = ConfigBase.config_parse_yaml(garbage) # response is a tuple... assert isinstance(result, tuple) # containing 2 items (plugins, config) assert len(result) == 2 # In the case of garbage in, we get garbage out; both lists are empty assert result == (list(), list()) # Invalid Version result, config = ConfigBase.config_parse_yaml("version: 2a", asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid Syntax (throws a ScannerError) result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Missing url token result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # No urls defined result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid url defined result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 # Invalid URL definition; yet the answer to life at the same time urls: 43 """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: - invalid:// """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: - invalid://: - a: b """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" # Include entry with nothing associated with it include: urls: - just some free text that isn't valid: - a garbage entry to go with it """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 urls: - not even a proper url """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" # no lists... just no urls: [milk, pumpkin pie, eggs, juice] # Including by list is okay include: [file:///absolute/path/, relative/path, http://test.com] """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were 3 include entries assert len(config) == 3 assert 'file:///absolute/path/' in config assert 'relative/path' in config assert 'http://test.com' in config # Invalid url/schema result, config = ConfigBase.config_parse_yaml(""" urls: # a very invalid sns entry - sns://T1JJ3T3L2/ - sns://:@/: - invalid: test - sns://T1JJ3T3L2/: - invalid: test # some strangeness - - - test """, asset=asset) # Invalid data gets us an empty result set assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # Valid Configuration result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed version: 1 # Including by dict include: # File includes - file:///absolute/path/ - relative/path # Trailing colon shouldn't disrupt include - http://test.com: # invalid (numeric) - 4 # some strangeness - - - test # # Define your notification urls: # urls: - pbul://o.gn5kj6nfhv736I7jC3cj3QLRiyhgl98b - mailto://test:[email protected] - https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG - https://not.a.native.url/ """, asset=asset) # We expect to parse 3 entries from the above # The Ryver one is in a native form and the 4th one is invalid assert isinstance(result, list) assert len(result) == 3 assert len(result[0].tags) == 0 # There were 3 include entries assert len(config) == 3 assert 'file:///absolute/path/' in config assert 'relative/path' in config assert 'http://test.com' in config # Valid Configuration result, config = ConfigBase.config_parse_yaml(""" # A single line include is supported include: http://localhost:8080/notify/apprise urls: - json://localhost: - tag: my-custom-tag, my-other-tag # How to stack multiple entries: - mailto://user:[email protected]: - to: [email protected] - to: [email protected] # This is an illegal entry; the schema can not be changed schema: json # accidently left a colon at the end of the url; no problem # we'll accept it - mailto://oscar:[email protected]: # A Ryver URL (using Native format); still accepted - https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG: # An invalid URL with colon (ignored) - https://not.a.native.url/: # A telegram entry (returns a None in parse_url()) - tgram://invalid """, asset=asset) # We expect to parse 4 entries from the above because the tgram:// entry # would have failed to be loaded assert isinstance(result, list) assert len(result) == 5 assert len(result[0].tags) == 2 # Our single line included assert len(config) == 1 assert 'http://localhost:8080/notify/apprise' in config # Global Tags result, config = ConfigBase.config_parse_yaml(""" # Global Tags stacked as a list tag: - admin - devops urls: - json://localhost - dbus:// """, asset=asset) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 2 # There were no include entries defined assert len(config) == 0 # all entries will have our global tags defined in them for entry in result: assert 'admin' in entry.tags assert 'devops' in entry.tags # Global Tags result, config = ConfigBase.config_parse_yaml(""" # Global Tags tag: admin, devops urls: # The following tags will get added to the global set - json://localhost: - tag: string-tag, my-other-tag, text # Tags can be presented in this list format too: - dbus://: - tag: - list-tag - dbus """, asset=asset) # all entries will have our global tags defined in them for entry in result: assert 'admin' in entry.tags assert 'devops' in entry.tags # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 2 # json:// has 2 globals + 3 defined assert len(result[0].tags) == 5 assert 'text' in result[0].tags # json:// has 2 globals + 2 defined assert len(result[1].tags) == 4 assert 'list-tag' in result[1].tags # There were no include entries defined assert len(config) == 0 # An invalid set of entries result, config = ConfigBase.config_parse_yaml(""" urls: # The following tags will get added to the global set - json://localhost: - - - entry """, asset=asset) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # An asset we'll manipulate asset = AppriseAsset() # Global Tags result, config = ConfigBase.config_parse_yaml(""" # Test the creation of our apprise asset object asset: app_id: AppriseTest app_desc: Apprise Test Notifications app_url: http://nuxref.com # Support setting empty values image_url_mask: image_url_logo: image_path_mask: tmp/path # invalid entry theme: - - - entry # Now for some invalid entries invalid: entry __init__: can't be over-ridden nolists: - we don't support these entries - in the apprise object urls: - json://localhost: """, asset=asset) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 1 # There were no include entries defined assert len(config) == 0 assert asset.app_id == "AppriseTest" assert asset.app_desc == "Apprise Test Notifications" assert asset.app_url == "http://nuxref.com" # the theme was not updated and remains the same as it was assert asset.theme == AppriseAsset().theme # Empty string assignment assert isinstance(asset.image_url_mask, six.string_types) is True assert asset.image_url_mask == "" assert isinstance(asset.image_url_logo, six.string_types) is True assert asset.image_url_logo == "" # For on-lookers looking through this file; here is a perfectly formatted # YAML configuration file for your reference so you can see it without # all of the errors like the ones identified above result, config = ConfigBase.config_parse_yaml(""" # if no version is specified then version 1 is presumed. Thus this is a # completely optional field. It's a good idea to just add this line because it # will help with future ambiguity (if it ever occurs). version: 1 # Define an Asset object if you wish (Optional) asset: app_id: AppriseTest app_desc: Apprise Test Notifications app_url: http://nuxref.com # Optionally define some global tags to associate with ALL of your # urls below. tag: admin, devops # Define your URLs (Mandatory!) urls: # Either on-line each entry like this: - json://localhost # Or add a colon to the end of the URL where you can optionally provide # over-ride entries. One of the most likely entry to be used here # is the tag entry. This gets extended to the global tag (if defined) # above - xml://localhost: - tag: customer # The more elements you specify under a URL the more times the URL will # get replicated and used. Hence this entry actually could be considered # 2 URLs being called with just the destination email address changed: - mailto://george:[email protected]: - to: [email protected] - to: [email protected] # Again... to re-iterate, the above mailto:// would actually fire two (2) # separate emails each with a different destination address specified. # Be careful when defining your arguments and differentiating between # when to use the dash (-) and when not to. Each time you do, you will # cause another instance to be created. # Defining more then 1 element to a muti-set is easy, it looks like this: - mailto://jackson:[email protected]: - to: [email protected] tag: jeff, customer - to: [email protected] tag: chris, customer """, asset=asset) # okay, here is how we get our total based on the above (read top-down) # +1 json:// entry # +1 xml:// entry # +2 mailto:// entry to [email protected] and [email protected] # +2 mailto:// entry to [email protected] and [email protected] # = 6 assert len(result) == 6 # all six entries will have our global tags defined in them for entry in result: assert 'admin' in entry.tags assert 'devops' in entry.tags # Entries can be directly accessed as they were added # our json:// had no additional tags added; so just the global ones # So just 2; admin and devops (these were already validated above in the # for loop assert len(result[0].tags) == 2 # our xml:// object has 1 tag added (customer) assert len(result[1].tags) == 3 assert 'customer' in result[1].tags # You get the idea, here is just a direct mapping to the remaining entries # in the same order they appear above assert len(result[2].tags) == 2 assert len(result[3].tags) == 2 assert len(result[4].tags) == 4 assert 'customer' in result[4].tags assert 'jeff' in result[4].tags assert len(result[5].tags) == 4 assert 'customer' in result[5].tags assert 'chris' in result[5].tags # There were no include entries defined assert len(config) == 0 # Valid Configuration (multi inline configuration entries) result, config = ConfigBase.config_parse_yaml(""" # A configuration file that contains 2 includes separated by a comma and/or # space: include: http://localhost:8080/notify/apprise, http://localhost/apprise/cfg """, asset=asset) # We will have loaded no results assert isinstance(result, list) assert len(result) == 0 # But our two configuration files will be present: assert len(config) == 2 assert 'http://localhost:8080/notify/apprise' in config assert 'http://localhost/apprise/cfg' in config # Valid Configuration (another way of specifying more then one include) result, config = ConfigBase.config_parse_yaml(""" # A configuration file that contains 4 includes on their own # lines beneath the keyword `include`: include: http://localhost:8080/notify/apprise http://localhost/apprise/cfg01 http://localhost/apprise/cfg02 http://localhost/apprise/cfg03 """, asset=asset) # We will have loaded no results assert isinstance(result, list) assert len(result) == 0 # But our 4 configuration files will be present: assert len(config) == 4 assert 'http://localhost:8080/notify/apprise' in config assert 'http://localhost/apprise/cfg01' in config assert 'http://localhost/apprise/cfg02' in config assert 'http://localhost/apprise/cfg03' in config # Valid Configuration (we allow comma separated entries for # each defined bullet) result, config = ConfigBase.config_parse_yaml(""" # A configuration file that contains 4 includes on their own # lines beneath the keyword `include`: include: - http://localhost:8080/notify/apprise, http://localhost/apprise/cfg01 http://localhost/apprise/cfg02 - http://localhost/apprise/cfg03 """, asset=asset) # We will have loaded no results assert isinstance(result, list) assert len(result) == 0 # But our 4 configuration files will be present: assert len(config) == 4 assert 'http://localhost:8080/notify/apprise' in config assert 'http://localhost/apprise/cfg01' in config assert 'http://localhost/apprise/cfg02' in config assert 'http://localhost/apprise/cfg03' in config
def test_config_base_config_parse_text(): """ API: ConfigBase.config_parse_text object """ # Garbage Handling for garbage in (object(), None, 42): # A response is always correctly returned result = ConfigBase.config_parse_text(garbage) # response is a tuple... assert isinstance(result, tuple) # containing 2 items (plugins, config) assert len(result) == 2 # In the case of garbage in, we get garbage out; both lists are empty assert result == (list(), list()) # Valid Configuration result, config = ConfigBase.config_parse_text(""" # A comment line over top of a URL mailto://userb:[email protected] # Test a URL using it's native format; in this case Ryver https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG # Invalid URL as it's not associated with a plugin # or a native url https://not.a.native.url/ # A line with mulitiple tag assignments to it taga,tagb=kde:// # An include statement to Apprise API with trailing spaces: include http://localhost:8080/notify/apprise # A relative include statement (with trailing spaces) include apprise.cfg """, asset=AppriseAsset()) # We expect to parse 3 entries from the above assert isinstance(result, list) assert isinstance(config, list) assert len(result) == 3 assert len(result[0].tags) == 0 # Our last element will have 2 tags associated with it assert len(result[-1].tags) == 2 assert 'taga' in result[-1].tags assert 'tagb' in result[-1].tags assert len(config) == 2 assert 'http://localhost:8080/notify/apprise' in config assert 'apprise.cfg' in config # Here is a similar result set however this one has an invalid line # in it which invalidates the entire file result, config = ConfigBase.config_parse_text(""" # A comment line over top of a URL mailto://userc:[email protected] # A line with mulitiple tag assignments to it taga,tagb=windows:// I am an invalid line that does not follow any of the Apprise file rules! """) # We expect to parse 0 entries from the above because the invalid line # invalidates the entire configuration file. This is for security reasons; # we don't want to point at files load content in them just because they # resemble an Apprise configuration. assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0 # More invalid data result, config = ConfigBase.config_parse_text(""" # An invalid URL invalid://user:[email protected] # A tag without a url taga= # A very poorly structured url sns://:@/ # Just 1 token provided sns://T1JJ3T3L2/ # Even with the above invalid entries, we can still # have valid include lines include file:///etc/apprise.cfg # An invalid include (nothing specified afterwards) include # An include of a config type we don't support include invalid:// """) # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # There was 1 valid entry assert len(config) == 0 # Test case where a comment is on it's own line with nothing else result, config = ConfigBase.config_parse_text("#") # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # There were no include entries defined assert len(config) == 0
def test_config_base_config_parse(): """ API: ConfigBase.config_parse """ # Garbage Handling for garbage in (object(), None, 42): # A response is always correctly returned result = ConfigBase.config_parse(garbage) # response is a tuple... assert isinstance(result, tuple) # containing 2 items (plugins, config) assert len(result) == 2 # In the case of garbage in, we get garbage out; both lists are empty assert result == (list(), list()) # Valid Text Configuration result = ConfigBase.config_parse(""" # A comment line over top of a URL mailto://userb:[email protected] """, asset=AppriseAsset()) # We expect to parse 1 entry from the above assert isinstance(result, tuple) assert len(result) == 2 # The first element is the number of notification services processed assert len(result[0]) == 1 # If we index into the item, we can check to see the tags associate # with it assert len(result[0][0].tags) == 0 # The second is the number of configuration include lines parsed assert len(result[1]) == 0 # Valid Configuration result = ConfigBase.config_parse(""" # if no version is specified then version 1 is presumed version: 1 # # Define your notification urls: # urls: - pbul://o.gn5kj6nfhv736I7jC3cj3QLRiyhgl98b - mailto://test:[email protected] - syslog://: - tag: devops, admin """, asset=AppriseAsset()) # We expect to parse 3 entries from the above assert isinstance(result, tuple) assert len(result) == 2 assert isinstance(result[0], list) assert len(result[0]) == 3 assert len(result[0][0].tags) == 0 assert len(result[0][1].tags) == 0 assert len(result[0][2].tags) == 2 # Test case where we pass in a bad format result = ConfigBase.config_parse(""" ; A comment line over top of a URL mailto://userb:[email protected] """, config_format='invalid-format') # This is not parseable despite the valid text assert isinstance(result, tuple) assert isinstance(result[0], list) assert len(result[0]) == 0 result, _ = ConfigBase.config_parse(""" ; A comment line over top of a URL mailto://userb:[email protected] """, config_format=ConfigFormat.TEXT) # Parseable assert isinstance(result, list) assert len(result) == 1
def test_config_base_config_parse_text(): """ API: ConfigBase.config_parse_text object """ # Garbage Handling assert isinstance(ConfigBase.config_parse_text(object()), list) assert isinstance(ConfigBase.config_parse_text(None), list) assert isinstance(ConfigBase.config_parse_text(''), list) # Valid Configuration result = ConfigBase.config_parse_text(""" # A comment line over top of a URL mailto://userb:[email protected] # Test a URL using it's native format; in this case Ryver https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG # Invalid URL as it's not associated with a plugin # or a native url https://not.a.native.url/ # A line with mulitiple tag assignments to it taga,tagb=kde:// """, asset=AppriseAsset()) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 3 assert len(result[0].tags) == 0 # Our last element will have 2 tags associated with it assert len(result[-1].tags) == 2 assert 'taga' in result[-1].tags assert 'tagb' in result[-1].tags # Here is a similar result set however this one has an invalid line # in it which invalidates the entire file result = ConfigBase.config_parse_text(""" # A comment line over top of a URL mailto://userc:[email protected] # A line with mulitiple tag assignments to it taga,tagb=windows:// I am an invalid line that does not follow any of the Apprise file rules! """) # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # More invalid data result = ConfigBase.config_parse_text(""" # An invalid URL invalid://user:[email protected] # A tag without a url taga= # A very poorly structured url sns://:@/ # Just 1 token provided sns://T1JJ3T3L2/ """) # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # Here is an empty file result = ConfigBase.config_parse_text('') # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # Test case where a comment is on it's own line with nothing else result = ConfigBase.config_parse_text("#") # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0 # Test case of empty file result = ConfigBase.config_parse_text("") # We expect to parse 0 entries from the above assert isinstance(result, list) assert len(result) == 0
def test_apprise_attachment(): """ API: AppriseAttachment basic testing """ # Create ourselves an attachment object aa = AppriseAttachment() # There are no attachents loaded assert len(aa) == 0 # Object can be directly checked as a boolean; response is False # when there are no entries loaded assert not aa # An attachment object using a custom Apprise Asset object # Set a cache expiry of 5 minutes (300 seconds) aa = AppriseAttachment(asset=AppriseAsset(), cache=300) # still no attachments added assert len(aa) == 0 # Add a file by it's path path = join(TEST_VAR_DIR, 'apprise-test.gif') assert aa.add(path) # There is now 1 attachment assert len(aa) == 1 # our attachment took on our cache value assert aa[0].cache == 300 # we can test the object as a boolean and get a value of True now assert aa # Add another entry already in it's AttachBase format response = AppriseAttachment.instantiate(path, cache=True) assert isinstance(response, AttachBase) assert aa.add(response, asset=AppriseAsset()) # There is now 2 attachments assert len(aa) == 2 # Cache is initialized to True assert aa[1].cache is True # Reset our object aa = AppriseAttachment() # We can add by lists as well in a variety of formats attachments = ( path, 'file://{}?name=newfilename.gif?cache=120'.format(path), AppriseAttachment.instantiate( 'file://{}?name=anotherfilename.gif'.format(path), cache=100), ) # Add them assert aa.add(attachments, cache=False) # There is now 3 attachments assert len(aa) == 3 # Take on our fixed cache value of False. # The last entry will have our set value of 100 assert aa[0].cache is False # Even though we set a value of 120, we take on the value of False because # it was forced on the instantiate call assert aa[1].cache is False assert aa[2].cache == 100 # We can pop the last element off of the list as well attachment = aa.pop() assert isinstance(attachment, AttachBase) # we can test of the attachment is valid using a boolean check: assert attachment assert len(aa) == 2 assert attachment.path == path assert attachment.name == 'anotherfilename.gif' assert attachment.mimetype == 'image/gif' # elements can also be directly indexed assert isinstance(aa[0], AttachBase) assert isinstance(aa[1], AttachBase) with pytest.raises(IndexError): aa[2] # We can iterate over attachments too: for count, a in enumerate(aa): assert isinstance(a, AttachBase) # we'll never iterate more then the number of entries in our object assert count < len(aa) # Get the file-size of our image expected_size = getsize(path) * len(aa) # verify that's what we get as a result assert aa.size() == expected_size # Attachments can also be loaded during the instantiation of the # AppriseAttachment object aa = AppriseAttachment(attachments) # There is now 3 attachments assert len(aa) == 3 # Reset our object aa.clear() assert len(aa) == 0 assert not aa assert aa.add(AppriseAttachment.instantiate( 'file://{}?name=andanother.png&cache=Yes'.format(path))) assert aa.add(AppriseAttachment.instantiate( 'file://{}?name=andanother.png&cache=No'.format(path))) AppriseAttachment.instantiate( 'file://{}?name=andanother.png&cache=600'.format(path)) assert aa.add(AppriseAttachment.instantiate( 'file://{}?name=andanother.png&cache=600'.format(path))) assert len(aa) == 3 assert aa[0].cache is True assert aa[1].cache is False assert aa[2].cache == 600 # Negative cache are not allowed assert not aa.add(AppriseAttachment.instantiate( 'file://{}?name=andanother.png&cache=-600'.format(path))) # Invalid cache value assert not aa.add(AppriseAttachment.instantiate( 'file://{}?name=andanother.png'.format(path), cache='invalid')) # No length change assert len(aa) == 3 # Reset our object aa.clear() # if instantiating attachments from the class, it will throw a TypeError # if attachments couldn't be loaded with pytest.raises(TypeError): AppriseAttachment('garbage://') # Garbage in produces garbage out assert aa.add(None) is False assert aa.add(object()) is False assert aa.add(42) is False # length remains unchanged assert len(aa) == 0 # We can add by lists as well in a variety of formats attachments = ( None, object(), 42, 'garbage://', ) # Add our attachments assert aa.add(attachments) is False # length remains unchanged assert len(aa) == 0 # test cases when file simply doesn't exist aa = AppriseAttachment('file://non-existant-file.png') # Our length is still 1 assert len(aa) == 1 # Our object will still return a True assert aa # However our indexed entry will not assert not aa[0] # length will return 0 assert len(aa[0]) == 0 # Total length will also return 0 assert aa.size() == 0
def test_config_base_config_parse(): """ API: ConfigBase.config_parse """ # Garbage Handling assert isinstance(ConfigBase.config_parse(object()), list) assert isinstance(ConfigBase.config_parse(None), list) assert isinstance(ConfigBase.config_parse(''), list) assert isinstance(ConfigBase.config_parse(12), list) # Valid Text Configuration result = ConfigBase.config_parse(""" # A comment line over top of a URL mailto://userb:[email protected] """, asset=AppriseAsset()) # We expect to parse 1 entry from the above assert isinstance(result, list) assert len(result) == 1 assert len(result[0].tags) == 0 # Valid Configuration result = ConfigBase.config_parse(""" # if no version is specified then version 1 is presumed version: 1 # # Define your notification urls: # urls: - pbul://o.gn5kj6nfhv736I7jC3cj3QLRiyhgl98b - mailto://test:[email protected] - syslog://: - tag: devops, admin """, asset=AppriseAsset()) # We expect to parse 3 entries from the above assert isinstance(result, list) assert len(result) == 3 assert len(result[0].tags) == 0 assert len(result[1].tags) == 0 assert len(result[2].tags) == 2 # Test case where we pass in a bad format result = ConfigBase.config_parse(""" ; A comment line over top of a URL mailto://userb:[email protected] """, config_format='invalid-format') # This is not parseable despite the valid text assert isinstance(result, list) assert len(result) == 0 result = ConfigBase.config_parse(""" ; A comment line over top of a URL mailto://userb:[email protected] """, config_format=ConfigFormat.TEXT) # Parseable assert isinstance(result, list) assert len(result) == 1
def test_config_file(tmpdir): """ API: ConfigFile() object """ assert ConfigFile.parse_url('garbage://') is None # Test cases where our URL is invalid t = tmpdir.mkdir("testing").join("apprise") t.write("gnome://") assert ConfigFile.parse_url('file://?') is None # Create an Apprise asset we can reference asset = AppriseAsset() # Initialize our object cf = ConfigFile(path=str(t), format='text', asset=asset) # one entry added assert len(cf) == 1 assert isinstance(cf.url(), six.string_types) is True # Verify that we're using the same asset assert cf[0].asset is asset # Testing of pop cf = ConfigFile(path=str(t), format='text') ref = cf[0] assert isinstance(ref, NotifyBase) is True ref_popped = cf.pop(0) assert isinstance(ref_popped, NotifyBase) is True assert ref == ref_popped assert len(cf) == 0 # reference to calls on initial reference cf = ConfigFile(path=str(t), format='text') assert isinstance(cf.pop(0), NotifyBase) is True cf = ConfigFile(path=str(t), format='text') assert isinstance(cf[0], NotifyBase) is True # Second reference actually uses cache assert isinstance(cf[0], NotifyBase) is True cf = ConfigFile(path=str(t), format='text') # Itereator creation (nothing needed to assert here) iter(cf) # Second reference actually uses cache iter(cf) # Cache Handling; cache each request for 30 seconds results = ConfigFile.parse_url('file://{}?cache=30'.format(str(t))) assert isinstance(results, dict) cf = ConfigFile(**results) assert isinstance(cf.url(), six.string_types) is True assert isinstance(cf.read(), six.string_types) is True