mirror of
https://github.com/aljazceru/plugins.git
synced 2025-12-19 14:14:20 +01:00
216 lines
9.7 KiB
Python
216 lines
9.7 KiB
Python
import os
|
|
import shelve
|
|
import time
|
|
import pytest
|
|
from pyln.testing.fixtures import * # noqa: F401,F403
|
|
from pyln.client import RpcError
|
|
from pyln.testing.utils import only_one, wait_for
|
|
|
|
plugin_path = os.path.join(os.path.dirname(__file__), "datastore.py")
|
|
|
|
|
|
# Test taken from lightning/tests/test_misc.py
|
|
def test_datastore(node_factory):
|
|
l1 = node_factory.get_node(options={'plugin': plugin_path})
|
|
time.sleep(5)
|
|
|
|
# Starts empty
|
|
assert l1.rpc.listdatastore() == {'datastore': []}
|
|
assert l1.rpc.listdatastore('somekey') == {'datastore': []}
|
|
|
|
# Add entries.
|
|
somedata = b'somedata'.hex()
|
|
somedata_expect = {'key': ['somekey'],
|
|
'generation': 0,
|
|
'hex': somedata,
|
|
'string': 'somedata'}
|
|
assert l1.rpc.datastore(key='somekey', hex=somedata) == somedata_expect
|
|
|
|
assert l1.rpc.listdatastore() == {'datastore': [somedata_expect]}
|
|
assert l1.rpc.listdatastore('somekey') == {'datastore': [somedata_expect]}
|
|
assert l1.rpc.listdatastore('otherkey') == {'datastore': []}
|
|
|
|
# Cannot add by default.
|
|
with pytest.raises(RpcError, match='already exists'):
|
|
l1.rpc.datastore(key='somekey', hex=somedata)
|
|
|
|
with pytest.raises(RpcError, match='already exists'):
|
|
l1.rpc.datastore(key='somekey', hex=somedata, mode="must-create")
|
|
|
|
# But can insist on replace.
|
|
l1.rpc.datastore(key='somekey', hex=somedata[:-4], mode="must-replace")
|
|
assert only_one(l1.rpc.listdatastore('somekey')['datastore'])['hex'] == somedata[:-4]
|
|
# And append works.
|
|
l1.rpc.datastore(key='somekey', hex=somedata[-4:-2], mode="must-append")
|
|
assert only_one(l1.rpc.listdatastore('somekey')['datastore'])['hex'] == somedata[:-2]
|
|
l1.rpc.datastore(key='somekey', hex=somedata[-2:], mode="create-or-append")
|
|
assert only_one(l1.rpc.listdatastore('somekey')['datastore'])['hex'] == somedata
|
|
|
|
# Generation will have increased due to three ops above.
|
|
somedata_expect['generation'] += 3
|
|
assert l1.rpc.listdatastore() == {'datastore': [somedata_expect]}
|
|
|
|
# Can't replace or append non-existing records if we say not to
|
|
with pytest.raises(RpcError, match='does not exist'):
|
|
l1.rpc.datastore(key='otherkey', hex=somedata, mode="must-replace")
|
|
|
|
with pytest.raises(RpcError, match='does not exist'):
|
|
l1.rpc.datastore(key='otherkey', hex=somedata, mode="must-append")
|
|
|
|
otherdata = b'otherdata'.hex()
|
|
otherdata_expect = {'key': ['otherkey'],
|
|
'generation': 0,
|
|
'hex': otherdata,
|
|
'string': 'otherdata'}
|
|
assert l1.rpc.datastore(key='otherkey', string='otherdata', mode="create-or-append") == otherdata_expect
|
|
|
|
assert l1.rpc.listdatastore('somekey') == {'datastore': [somedata_expect]}
|
|
assert l1.rpc.listdatastore('otherkey') == {'datastore': [otherdata_expect]}
|
|
assert l1.rpc.listdatastore('badkey') == {'datastore': []}
|
|
|
|
ds = l1.rpc.listdatastore()
|
|
# Order is undefined!
|
|
assert (ds == {'datastore': [somedata_expect, otherdata_expect]}
|
|
or ds == {'datastore': [otherdata_expect, somedata_expect]})
|
|
|
|
assert l1.rpc.deldatastore('somekey') == somedata_expect
|
|
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
|
assert l1.rpc.listdatastore('somekey') == {'datastore': []}
|
|
assert l1.rpc.listdatastore('otherkey') == {'datastore': [otherdata_expect]}
|
|
assert l1.rpc.listdatastore('badkey') == {'datastore': []}
|
|
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
|
|
|
# if it's not a string, won't print
|
|
badstring_expect = {'key': ['badstring'],
|
|
'generation': 0,
|
|
'hex': '00'}
|
|
assert l1.rpc.datastore(key='badstring', hex='00') == badstring_expect
|
|
assert l1.rpc.listdatastore('badstring') == {'datastore': [badstring_expect]}
|
|
assert l1.rpc.deldatastore('badstring') == badstring_expect
|
|
|
|
# It's persistent
|
|
l1.restart()
|
|
|
|
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
|
|
|
# We can insist generation match on update.
|
|
with pytest.raises(RpcError, match='generation is different'):
|
|
l1.rpc.datastore(key='otherkey', hex='00', mode='must-replace',
|
|
generation=otherdata_expect['generation'] + 1)
|
|
|
|
otherdata_expect['generation'] += 1
|
|
otherdata_expect['string'] += 'a'
|
|
otherdata_expect['hex'] += '61'
|
|
assert (l1.rpc.datastore(key='otherkey', string='otherdataa',
|
|
mode='must-replace',
|
|
generation=otherdata_expect['generation'] - 1)
|
|
== otherdata_expect)
|
|
assert l1.rpc.listdatastore() == {'datastore': [otherdata_expect]}
|
|
|
|
# We can insist generation match on delete.
|
|
with pytest.raises(RpcError, match='generation is different'):
|
|
l1.rpc.deldatastore(key='otherkey',
|
|
generation=otherdata_expect['generation'] + 1)
|
|
|
|
assert (l1.rpc.deldatastore(key='otherkey',
|
|
generation=otherdata_expect['generation'])
|
|
== otherdata_expect)
|
|
assert l1.rpc.listdatastore() == {'datastore': []}
|
|
|
|
|
|
def test_upgrade(node_factory):
|
|
l1 = node_factory.get_node()
|
|
|
|
datastore = shelve.open(os.path.join(l1.daemon.lightning_dir, 'regtest', 'datastore.dat'), 'c')
|
|
datastore['foo'] = b'foodata'
|
|
datastore['bar'] = b'bardata'
|
|
datastore.close()
|
|
|
|
# This "fails" because it unloads itself.
|
|
try:
|
|
l1.rpc.plugin_start(plugin_path)
|
|
except RpcError:
|
|
pass
|
|
|
|
# There's no upgrade if there's a real datastore.
|
|
if l1.daemon.is_in_log('there is a real datastore command'):
|
|
return
|
|
|
|
l1.daemon.wait_for_log('Upgrading store to have generation numbers')
|
|
wait_for(lambda: not os.path.exists(os.path.join(l1.daemon.lightning_dir,
|
|
'regtest',
|
|
'datastore.dat')))
|
|
|
|
vals = l1.rpc.listdatastore()['datastore']
|
|
assert vals == [{'key': ['bar'],
|
|
'generation': 0,
|
|
'hex': b'bardata'.hex(),
|
|
'string': 'bardata'},
|
|
{'key': ['foo'],
|
|
'generation': 0,
|
|
'hex': b'foodata'.hex(),
|
|
'string': 'foodata'}]
|
|
|
|
|
|
def test_datastore_keylist(node_factory):
|
|
l1 = node_factory.get_node(options={'plugin': plugin_path})
|
|
time.sleep(5)
|
|
|
|
# Starts empty
|
|
assert l1.rpc.listdatastore() == {'datastore': []}
|
|
assert l1.rpc.listdatastore(['a']) == {'datastore': []}
|
|
assert l1.rpc.listdatastore(['a', 'b']) == {'datastore': []}
|
|
|
|
# Cannot add child to existing!
|
|
l1.rpc.datastore(key='a', string='aval')
|
|
with pytest.raises(RpcError, match=r'1206.*Parent key \[a\] exists'):
|
|
l1.rpc.datastore(key=['a', 'b'], string='abval',
|
|
mode='create-or-replace')
|
|
# Listing subkey gives DNE.
|
|
assert l1.rpc.listdatastore(['a', 'b']) == {'datastore': []}
|
|
l1.rpc.deldatastore(key=['a'])
|
|
|
|
# Create child key.
|
|
l1.rpc.datastore(key=['a', 'b'], string='abval')
|
|
assert l1.rpc.listdatastore() == {'datastore': [{'key': ['a']}]}
|
|
assert l1.rpc.listdatastore(key=['a']) == {'datastore': [{'key': ['a', 'b'],
|
|
'generation': 0,
|
|
'string': 'abval',
|
|
'hex': b'abval'.hex()}]}
|
|
|
|
# Cannot create key over that
|
|
with pytest.raises(RpcError, match='has children'):
|
|
l1.rpc.datastore(key='a', string='aval', mode='create-or-replace')
|
|
|
|
# Can create another key.
|
|
l1.rpc.datastore(key=['a', 'b2'], string='ab2val')
|
|
assert l1.rpc.listdatastore() == {'datastore': [{'key': ['a']}]}
|
|
assert l1.rpc.listdatastore(key=['a']) == {'datastore': [{'key': ['a', 'b'],
|
|
'string': 'abval',
|
|
'generation': 0,
|
|
'hex': b'abval'.hex()},
|
|
{'key': ['a', 'b2'],
|
|
'string': 'ab2val',
|
|
'generation': 0,
|
|
'hex': b'ab2val'.hex()}]}
|
|
|
|
# Can create subkey.
|
|
l1.rpc.datastore(key=['a', 'b3', 'c'], string='ab2val')
|
|
assert l1.rpc.listdatastore() == {'datastore': [{'key': ['a']}]}
|
|
assert l1.rpc.listdatastore(key=['a']) == {'datastore': [{'key': ['a', 'b'],
|
|
'string': 'abval',
|
|
'generation': 0,
|
|
'hex': b'abval'.hex()},
|
|
{'key': ['a', 'b2'],
|
|
'string': 'ab2val',
|
|
'generation': 0,
|
|
'hex': b'ab2val'.hex()},
|
|
{'key': ['a', 'b3']}]}
|
|
|
|
# Can update subkey
|
|
l1.rpc.datastore(key=['a', 'b3', 'c'], string='2', mode='must-append')
|
|
assert l1.rpc.listdatastore(key=['a', 'b3', 'c']) == {'datastore': [{'key': ['a', 'b3', 'c'],
|
|
'string': 'ab2val2',
|
|
'generation': 1,
|
|
'hex': b'ab2val2'.hex()}]}
|