diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 46466acc5..70bb003e0 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -835,6 +835,71 @@ class LightningDTests(BaseLightningDTests): assert len(l1.rpc.listpayments(inv)['payments']) == 1 assert l1.rpc.listpayments(inv)['payments'][0]['payment_preimage'] == preimage['preimage'] + # Long test involving 4 lightningd instances. + @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") + def test_report_routing_failure(self): + """Test routing failure and retrying of routing. + """ + # The setup is as follows: + # l3-->l4 + # ^ / | + # | / | + # | L v + # l2<--l1 + # + # l1 wants to pay to l4. + # The shortest route is l1-l4, but l1 cannot + # afford to pay to l1 because l4 has all the + # funds. + # This is a local failure. + # The next shortest route is l1-l2-l4, but + # l2 cannot afford to pay l4 for same reason. + # This is a remote failure. + # Finally the only possible path is + # l1-l2-l3-l4. + + def fund_from_to_payer(lsrc, ldst, lpayer): + lsrc.rpc.connect(ldst.info['id'], 'localhost', ldst.info['port']) + c = self.fund_channel(lsrc, ldst, 10000000) + self.wait_for_routes(lpayer, [c]) + + # FIXME: This repeated retrying should get implemented + # in lightningd `pay` command directly. + def pay(l, inv): + start_time = time.time() + retry = True + err = None + while retry: + if time.time() > start_time + 10: + raise err + try: + l.rpc.pay(inv) + retry = False + except Exception as errx: + err = errx + + ## Setup + # Construct lightningd + l1 = self.node_factory.get_node() + l2 = self.node_factory.get_node() + l3 = self.node_factory.get_node() + l4 = self.node_factory.get_node() + + # Wire them up + # The ordering below matters! + # Particularly, l1 is payer and we will + # wait for l1 to receive gossip for the + # channel being made. + fund_from_to_payer(l1, l2, l1) + fund_from_to_payer(l2, l3, l1) + fund_from_to_payer(l3, l4, l1) + fund_from_to_payer(l4, l1, l1) + fund_from_to_payer(l4, l2, l1) + + ## Test + inv = l4.rpc.invoice(1234567, 'inv', 'for testing')['bolt11'] + pay(l1, inv) + def test_bad_opening(self): # l1 asks for a too-long locktime l1 = self.node_factory.get_node(options=['--locktime-blocks=100'])