Browse Source

completed coverage of jmclient

master
Adam Gibson 9 years ago
parent
commit
e288ba92e9
No known key found for this signature in database
GPG Key ID: B3AE09F1E9A3197A
  1. 7
      jmclient/jmclient/client_protocol.py
  2. 13
      jmclient/jmclient/configure.py
  3. 1
      jmclient/test/.coveragerc
  4. 246
      jmclient/test/test_client_protocol.py
  5. 58
      jmclient/test/test_commitment_utils.py
  6. 21
      jmclient/test/test_configure.py
  7. 3
      jmclient/test/test_wallets.py

7
jmclient/jmclient/client_protocol.py

@ -58,10 +58,13 @@ class JMTakerClientProtocol(amp.AMP):
is considered criticial.
"""
if 'accepted' not in response or not response['accepted']:
reactor.stop()
#Unintended client shutdown cannot be tested easily in twisted
reactor.stop() #pragma: no cover
def defaultErrback(self, failure):
failure.trap(ConnectionAborted, ConnectionClosed, ConnectionDone, ConnectionLost)
#see testing note above
failure.trap(ConnectionAborted, ConnectionClosed, ConnectionDone,
ConnectionLost) #pragma: no cover
def defaultCallbacks(self, d):
d.addCallback(self.checkClientResponse)

13
jmclient/jmclient/configure.py

@ -306,12 +306,15 @@ def load_program_config(config_path=None, bs=None):
configfile.write(defaultconfig)
# check for sections
for s in required_options:
#These are left as sanity checks but currently impossible
#since any edits are overlays to the default, these sections/options will
#always exist.
for s in required_options: #pragma: no cover
if s not in global_singleton.config.sections():
raise Exception(
"Config file does not contain the required section: " + s)
# then check for specific options
for k, v in required_options.iteritems():
for k, v in required_options.iteritems(): #pragma: no cover
for o in v:
if o not in global_singleton.config.options(k):
raise Exception(
@ -320,7 +323,7 @@ def load_program_config(config_path=None, bs=None):
try:
global_singleton.maker_timeout_sec = global_singleton.config.getint(
'TIMEOUT', 'maker_timeout_sec')
except NoOptionError:
except NoOptionError: #pragma: no cover
log.debug('TIMEOUT/maker_timeout_sec not found in .cfg file, '
'using default value')
@ -332,9 +335,9 @@ def load_program_config(config_path=None, bs=None):
try:
global_singleton.commit_file_location = global_singleton.config.get(
"POLICY", "commit_file_location")
except NoOptionError:
except NoOptionError: #pragma: no cover
log.debug("No commitment file location in config, using default "
"location cmttools/commitments.json")
"location cmtdata/commitments.json")
set_commitment_file(os.path.join(config_path,
global_singleton.commit_file_location))

1
jmclient/test/.coveragerc

@ -2,4 +2,5 @@
[run]
omit =
../jmclient/jsonrpc.py
../jmclient/slowaes.py
../jmclient/btc.py

246
jmclient/test/test_client_protocol.py

@ -0,0 +1,246 @@
#! /usr/bin/env python
from __future__ import absolute_import
'''test client-protocol interfacae.'''
import pytest
from jmclient import (get_schedule, load_program_config, start_reactor,
Taker, get_log, JMTakerClientProtocolFactory, jm_single)
from jmclient.client_protocol import JMProtocolError, JMTakerClientProtocol
import os
from twisted.python.log import startLogging, err
from twisted.python.log import msg as tmsg
from twisted.internet import protocol, reactor
from twisted.internet.error import (ConnectionLost, ConnectionAborted,
ConnectionClosed, ConnectionDone)
from twisted.protocols.amp import UnknownRemoteError
from twisted.python import failure
from twisted.protocols import amp
from jmbase.commands import *
from taker_test_data import t_raw_signed_tx
import json
import time
import jmbitcoin as bitcoin
test_completed = False
clientfactory = None
runno = 0
jlog = get_log()
class DummyTaker(Taker):
def set_fail_init(self, val):
self.failinit = val
def set_fail_utxos(self, val):
self.failutxos = val
def default_taker_info_callback(self, infotype, msg):
jlog.debug(infotype + ":" + msg)
def initialize(self, orderbook):
"""Once the daemon is active and has returned the current orderbook,
select offers, re-initialize variables and prepare a commitment,
then send it to the protocol to fill offers.
"""
if self.failinit==-1:
return (True, -1, "aa"*32, {'dummy':'revelation'},orderbook[:2])
elif self.failinit:
return (False,)
else:
return (True, 1000000, "aa"*32, {'dummy':'revelation'},
orderbook[:2])
def receive_utxos(self, ioauth_data):
"""Triggered when the daemon returns utxo data from
makers who responded; this is the completion of phase 1
of the protocol
"""
if self.failutxos:
return (False, "dummyreason")
else:
return (True, [x*64 + ":01" for x in ["a", "b", "c"]], t_raw_signed_tx)
def on_sig(self, nick, sigb64):
jlog.debug("We got a sig: " + sigb64)
end_test()
return True
class JMBaseProtocol(amp.AMP):
def checkClientResponse(self, response):
"""A generic check of client acceptance; any failure
is considered criticial.
"""
if 'accepted' not in response or not response['accepted']:
reactor.stop()
def defaultErrback(self, failure):
failure.trap(ConnectionAborted, ConnectionClosed, ConnectionDone,
ConnectionLost, UnknownRemoteError)
reactor.stop()
def defaultCallbacks(self, d):
d.addCallback(self.checkClientResponse)
d.addErrback(self.defaultErrback)
def show_receipt(name, *args):
tmsg("Received msgtype: " + name + ", args: " + ",".join([str(x) for x in args]))
def end_client(client):
client.shutdown_requested = True
def end_test():
#global runno
global test_completed
#runno += 1
#jlog.info("Updated runno to: " + str(runno))
#taker = DummyTaker(None, None)
#if runno == 1:
# jlog.info("Run number was less than 2")
# taker.set_fail_init(True)
# taker.set_fail_utxos(False)
# cfactory = JMTakerClientProtocolFactory(taker)
# reactor.connectTCP("localhost", 27184, cfactory)
# return
#elif runno == 2:
# taker.set_fail_init(False)
# taker.set_fail_utxos(True)
# cfactory = JMTakerClientProtocolFactory(taker)
# reactor.connectTCP("localhost", 27184, cfactory)
# return
test_completed = True
client = clientfactory.getClient()
reactor.callLater(2, end_client, client)
class JMTestServerProtocol(JMBaseProtocol):
@JMInit.responder
def on_JM_INIT(self, bcsource, network, irc_configs, minmakers,
maker_timeout_sec):
show_receipt("JMINIT", bcsource, network, irc_configs, minmakers,
maker_timeout_sec)
d = self.callRemote(JMInitProto,
nick_hash_length=1,
nick_max_encoded=2,
joinmarket_nick_header="J",
joinmarket_version=5)
self.defaultCallbacks(d)
return {'accepted': True}
@JMStartMC.responder
def on_JM_START_MC(self, nick):
show_receipt("STARTMC", nick)
d = self.callRemote(JMUp)
self.defaultCallbacks(d)
return {'accepted': True}
@JMSetup.responder
def on_JM_SETUP(self, role, n_counterparties):
show_receipt("JMSETUP", role,n_counterparties)
d = self.callRemote(JMSetupDone)
self.defaultCallbacks(d)
return {'accepted': True}
@JMRequestOffers.responder
def on_JM_REQUEST_OFFERS(self):
show_receipt("JMREQUESTOFFERS")
#build a huge orderbook to test BigString Argument
orderbook = ["aaaa" for _ in range(15)]
d = self.callRemote(JMOffers,
orderbook=json.dumps(orderbook))
self.defaultCallbacks(d)
return {'accepted': True}
@JMFill.responder
def on_JM_FILL(self, amount, commitment, revelation, filled_offers):
success = False if amount == -1 else True
show_receipt("JMFILL", amount, commitment, revelation, filled_offers)
d = self.callRemote(JMFillResponse,
success=success,
ioauth_data = json.dumps(['dummy', 'list']))
return {'accepted': True}
@JMMakeTx.responder
def on_JM_MAKE_TX(self, nick_list, txhex):
show_receipt("JMMAKETX", nick_list, txhex)
d = self.callRemote(JMSigReceived,
nick="dummynick",
sig="xxxsig")
self.defaultCallbacks(d)
#add dummy calls to check message sign and message verify
d2 = self.callRemote(JMRequestMsgSig,
nick="dummynickforsign",
cmd="command1",
msg="msgforsign",
msg_to_be_signed="fullmsgforsign",
hostid="hostid1")
self.defaultCallbacks(d2)
#To test, this must include a valid ecdsa sig
fullmsg = "fullmsgforverify"
priv = "aa"*32 + "01"
pub = bitcoin.privkey_to_pubkey(priv)
sig = bitcoin.ecdsa_sign(fullmsg, priv)
d3 = self.callRemote(JMRequestMsgSigVerify,
msg="msgforverify",
fullmsg=fullmsg,
sig=sig,
pubkey=pub,
nick="dummynickforverify",
hashlen=4,
max_encoded=5,
hostid="hostid2")
self.defaultCallbacks(d3)
d4 = self.callRemote(JMSigReceived,
nick="dummynick",
sig="dummysig")
self.defaultCallbacks(d4)
return {'accepted': True}
@JMMsgSignature.responder
def on_JM_MSGSIGNATURE(self, nick, cmd, msg_to_return, hostid):
show_receipt("JMMSGSIGNATURE", nick, cmd, msg_to_return, hostid)
return {'accepted': True}
@JMMsgSignatureVerify.responder
def on_JM_MSGSIGNATURE_VERIFY(self, verif_result, nick, fullmsg, hostid):
show_receipt("JMMSGSIGVERIFY", verif_result, nick, fullmsg, hostid)
return {'accepted': True}
class JMTestServerProtocolFactory(protocol.ServerFactory):
protocol = JMTestServerProtocol
class DummyClientProtocolFactory(JMTakerClientProtocolFactory):
def buildProtocol(self, addr):
return JMTakerClientProtocol(self, self.taker, nick_priv="aa"*32)
def test_jm_protocol():
"""We cannot use parametrize for different options as
we can't run in sequence; hence, parameters hardcoded as lists here
"""
params = [[False, False], [True, False], [False, True], [-1, False]]
global clientfactory
load_program_config()
jm_single().maker_timeout_sec = 1
reactor.listenTCP(27184, JMTestServerProtocolFactory())
clientfactories = []
takers = [DummyTaker(None, None) for _ in range(len(params))]
for i, p in enumerate(params):
takers[i].set_fail_init(p[0])
takers[i].set_fail_utxos(p[1])
if i != 0:
clientfactories.append(JMTakerClientProtocolFactory(takers[i]))
reactor.connectTCP("localhost", 27184, clientfactories[i])
else:
clientfactories.append(DummyClientProtocolFactory(takers[i]))
clientfactory = clientfactories[0]
start_reactor("localhost", 27184, clientfactories[0])
print("Got here")
if not test_completed:
raise Exception("Failed test")

58
jmclient/test/test_commitment_utils.py

@ -0,0 +1,58 @@
#!/usr/bin/env python
from __future__ import print_function
from commontest import DummyBlockchainInterface
import pytest
from jmclient import (load_program_config, jm_single)
from jmclient.commitment_utils import get_utxo_info, validate_utxo_data
from taker_test_data import (t_utxos_by_mixdepth, t_selected_utxos, t_orderbook,
t_maker_response, t_chosen_orders, t_dummy_ext)
def test_get_utxo_info():
load_program_config()
jm_single().config.set("BLOCKCHAIN", "network", "mainnet")
dbci = DummyBlockchainInterface()
privkey = "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi"
#to verify use from_wif_privkey and privkey_to_address
iaddr = "1LDsjB43N2NAQ1Vbc2xyHca4iBBciN8iwC"
fakeutxo = "aa"*32+":08"
fake_query_results = [{'value': 200000000,
'address': iaddr,
'utxo': fakeutxo,
'confirms': 20}]
dbci.insert_fake_query_results(fake_query_results)
jm_single().bc_interface = dbci
u, priv = get_utxo_info(fakeutxo + "," + privkey)
assert u == fakeutxo
assert priv == privkey
#invalid format
with pytest.raises(Exception) as e_info:
u, priv = get_utxo_info(fakeutxo + privkey)
#invalid index
fu2 = "ab"*32 + ":00004"
with pytest.raises(Exception) as e_info:
u, priv = get_utxo_info(fu2 + "," + privkey)
#invalid privkey
p2 = privkey[:-1] + 'j'
with pytest.raises(Exception) as e_info:
u, priv = get_utxo_info(fakeutxo + "," + p2)
utxodatas = [(fakeutxo, privkey)]
retval = validate_utxo_data(utxodatas, False)
assert retval
#try to retrieve
retval = validate_utxo_data(utxodatas, True)
assert retval[0] == (fakeutxo, 200000000)
fake_query_results[0]['address'] = "fakeaddress"
dbci.insert_fake_query_results(fake_query_results)
#validate should fail for wrong address
retval = validate_utxo_data(utxodatas, False)
assert not retval
#remove fake query result and trigger not found
dbci.fake_query_results = None
dbci.setQUSFail(True)
retval = validate_utxo_data(utxodatas, False)
assert not retval
dbci.setQUSFail(False)

21
jmclient/test/test_configure.py

@ -1,6 +1,6 @@
#! /usr/bin/env python
from __future__ import absolute_import
'''test schedule module.'''
'''test configure module.'''
import pytest
from jmclient import (load_program_config, jm_single, get_irc_mchannels,
@ -12,6 +12,25 @@ import jmbitcoin as bitcoin
import copy
import os
def test_attribute_dict():
from jmclient.configure import AttributeDict
ad = AttributeDict(foo=1, bar=2, baz={"x":3, "y":4})
assert ad.foo == 1
assert ad.bar == 2
assert ad.baz.x == 3
assert ad["foo"] == 1
def test_load_config():
load_program_config(bs="regtest")
os.makedirs("dummydirforconfig")
ncp = os.path.join(os.getcwd(), "dummydirforconfig")
#need to erase remembered data in global config
jm_single().config_location = "joinmarket.cfg"
load_program_config(config_path=ncp)
os.remove("dummydirforconfig/joinmarket.cfg")
os.removedirs("dummydirforconfig")
jm_single().config_location = "joinmarket.cfg"
load_program_config()
def test_config_get_irc_channel():
load_program_config()

3
jmclient/test/test_wallets.py

@ -54,8 +54,9 @@ def test_query_utxo_set(setup_wallets):
["wallet4utxo.json", "4utxo", [2, 3]])
sync_wallet(wallet)
txid = do_tx(wallet, 90000000)
time.sleep(5)
time.sleep(3)
txid2 = do_tx(wallet, 20000000)
time.sleep(3)
print("Got txs: ", txid, txid2)
res1 = jm_single().bc_interface.query_utxo_set(txid + ":0")
res2 = jm_single().bc_interface.query_utxo_set(

Loading…
Cancel
Save