Repository: buidl-bitcoin/buidl-python (language: python)

Issue:
Get test_singlesweep.py and test_multiwallet.py working on github CI
They work for me locally but don't work on GitHub CI (I temporarily disabled them). Not sure if it's an OS issue or something else.
```
$ pytest test_*.py -v
========================================== test session starts ===========================================
platform darwin -- Python 3.9.0, pytest-6.1.1, py-1.10.0, pluggy-0.13.1 -- /Users/mflaxman/.pyenv/versions/3.9.0/bin/python3
cachedir: .pytest_cache
rootdir: /Users/mflaxman/workspace/buidl-python
collected 10 items                                                                                       

test_multiwallet.py::MultiwalletTest::test_change_addr PASSED                                      [ 10%]
test_multiwallet.py::MultiwalletTest::test_debug PASSED                                            [ 20%]
test_multiwallet.py::MultiwalletTest::test_fail PASSED                                             [ 30%]
test_multiwallet.py::MultiwalletTest::test_receive_addr PASSED                                     [ 40%]
test_multiwallet.py::MultiwalletTest::test_seedpicker_basic PASSED                                 [ 50%]
test_multiwallet.py::MultiwalletTest::test_sign_tx PASSED                                          [ 60%]
test_singlesweep.py::SinglesweepTest::test_debug PASSED                                            [ 70%]
test_singlesweep.py::SinglesweepTest::test_fail PASSED                                             [ 80%]
test_singlesweep.py::SinglesweepTest::test_send_compressed PASSED                                  [ 90%]
test_singlesweep.py::SinglesweepTest::test_send_uncompressed PASSED                                [100%]

=========================================== 10 passed in 9.71s ===========================================
```

PR here for more details:
https://github.com/buidl-bitcoin/buidl-python/pull/62#issuecomment-851845791


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 0a2e535..70583ae 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -35,3 +35,6 @@ jobs:
     - name: pytest unit tests
       run: |
         pytest -v buidl/test
+    - name: pytest CLI apps
+      run: |
+        pytest -v test_singlesweep.py test_multiwallet.py


Test patch:
diff --git a/test_multiwallet.py b/test_multiwallet.py
index 8d57078..9461944 100644
--- a/test_multiwallet.py
+++ b/test_multiwallet.py
@@ -4,19 +4,45 @@
 
 
 class MultiwalletTest(unittest.TestCase):
+    def expect(self, text):
+        """
+        Expect a string of bytes one at a time (not waiting on a newline)
+        """
+        buffer = ""
+        while True:
+
+            try:
+                # This will error out at the end of the buffer
+                latest_char = self.child.read(1)
+            except Exception as e:
+                print("buffer", buffer)
+                raise Exception(f"Failed to find text `{text}`in buffer. Error: {e}")
+
+            try:
+                latest_char = latest_char.decode()
+                if latest_char not in ("\n", "\r"):
+                    buffer += latest_char
+            except UnicodeDecodeError:
+                # Handle non-unicode char edge-case (bitcoin symbol)
+                buffer += str(latest_char)
+
+            if text in buffer:
+                return True
+
+        # this line should never be reached, the script would timeout first
+        assert f"`{text}` not in buffer: {buffer}"
+
     def setUp(self):
         self.child = pexpect.spawn("python3 multiwallet.py", timeout=2)
-        self.child.expect(
-            "Welcome to multiwallet, the stateless multisig bitcoin wallet"
-        )
+        self.expect("Welcome to multiwallet, the stateless multisig bitcoin wallet")
 
     def test_debug(self):
         self.child.sendline("debug")
-        self.child.expect("buidl Version: ")
-        self.child.expect("Multiwallet Mode: ")
-        self.child.expect("Python Version: ")
-        self.child.expect("Platform: ")
-        self.child.expect("libsecp256k1 Configured: ")
+        self.expect("buidl Version: ")
+        self.expect("Multiwallet Mode: ")
+        self.expect("Python Version: ")
+        self.expect("Platform: ")
+        self.expect("libsecp256k1 Configured: ")
 
     def test_seedpicker_basic(self):
         seedpicker_tests = [
@@ -32,65 +58,58 @@ def test_seedpicker_basic(self):
         ]
         for is_mainnet, expected_key_record in seedpicker_tests:
             self.child.sendline("generate_seed")
-            self.child.expect("Enter the first 23 words of your BIP39 seed phrase")
+            self.expect("Enter the first 23 words of your BIP39 seed phrase")
+
             self.child.sendline("bacon " * 23)
-            self.child.readline()
-            res = str(self.child.read(20))
-            self.assertIn("Use Mainnet?", res)
+            self.expect("Use Mainnet?")
+
             self.child.sendline(is_mainnet)
-            self.child.expect("Last word: bacon")
-            for _ in range(5):
-                self.child.readline()
-            res = str(self.child.readline())
-            self.assertIn(expected_key_record, res)
+            self.expect("Last word: bacon")
+            self.expect(expected_key_record)
 
     def test_receive_addr(self):
         account_map = "wsh(sortedmulti(1,[aa917e75/48h/1h/0h/2h]tpubDEZRP2dRKoGRJnR9zn6EoLouYKbYyjFsxywgG7wMQwCDVkwNvoLhcX1rTQipYajmTAF82kJoKDiNCgD4wUPahACE7n1trMSm7QS8B3S1fdy/0/*,[2553c4b8/48h/1h/0h/2h]tpubDEiNuxUt4pKjKk7khdv9jfcS92R1WQD6Z3dwjyMFrYj2iMrYbk3xB5kjg6kL4P8SoWsQHpd378RCTrM7fsw4chnJKhE2kfbfc4BCPkVh6g9/0/*))#t0v98kwu"
         receive_addr = "tb1qtsvps7q8j5mn2qqfrujlrnwraelkptps5k595hn5d4tfq7mv644sfkkxps"
 
         self.child.sendline("receive")
-        for _ in range(6):
-            self.child.readline()
-        res = str(self.child.read(50))
-        self.assertIn("Paste in your account map (AKA output record)", res)
+        self.expect("Paste in your account map (AKA output record")
+
         self.child.sendline(account_map)
-        self.child.readline()
-        res = str(self.child.read(40))
-        self.assertIn("Limit of addresses to display", res)
+        self.expect("Limit of addresses to display")
+
         self.child.sendline("1")
-        self.child.readline()
-        res = str(self.child.read(40))
-        self.assertIn("Offset of addresses to display", res)
+        self.expect("Offset of addresses to display")
+
         self.child.sendline("0")
-        self.child.expect("1-of-2 Multisig Receive Addresses")
-        self.child.expect(receive_addr)
+        self.expect("1-of-2 Multisig Receive Addresses")
+        self.expect(receive_addr)
 
     def test_change_addr(self):
         account_map = "wsh(sortedmulti(1,[aa917e75/48h/1h/0h/2h]tpubDEZRP2dRKoGRJnR9zn6EoLouYKbYyjFsxywgG7wMQwCDVkwNvoLhcX1rTQipYajmTAF82kJoKDiNCgD4wUPahACE7n1trMSm7QS8B3S1fdy/0/*,[2553c4b8/48h/1h/0h/2h]tpubDEiNuxUt4pKjKk7khdv9jfcS92R1WQD6Z3dwjyMFrYj2iMrYbk3xB5kjg6kL4P8SoWsQHpd378RCTrM7fsw4chnJKhE2kfbfc4BCPkVh6g9/0/*))#t0v98kwu"
         change_addr = "tb1qjcsz3nmscxdecksnrn5k9dxrj0g3f7xkuclk53aqu33lg06r0cks5l8ew8"
 
         self.child.sendline("advanced_mode")
-        self.child.expect("ADVANCED mode set")
+        self.expect("ADVANCED mode set")
+
         self.child.sendline("receive")
-        self.child.readline()
-        self.child.readline()
-        res = str(self.child.read(50))
-        self.assertIn("Paste in your account map (AKA output record)", res)
+        self.expect("Paste in your account map (AKA output record)")
+
         self.child.sendline(account_map)
-        self.child.readline()
-        res = str(self.child.read(40))
-        self.assertIn("Limit of addresses to display", res)
+        self.expect("Limit of addresses to display")
+
         self.child.sendline("1")
-        self.child.readline()
-        res = str(self.child.read(40))
-        self.assertIn("Offset of addresses to display", res)
+        self.expect("Offset of addresses to display")
+
         self.child.sendline("0")
-        self.child.readline()
-        res = str(self.child.read(80))
-        self.assertIn("Display receive addresses?", res)
+        # UGLY HACK
+        # Line reads:
+        #   Display receive addresses? `N` to display change addresses instead. [Y/n]:
+        # But Github CI uses a very narrow terminal and only picks this part up:
+        self.expect("to display change addresses instead")
+
         self.child.sendline("N")
-        self.child.expect("1-of-2 Multisig Change Addresses")
-        self.child.expect(change_addr)
+        self.expect("1-of-2 Multisig Change Addresses")
+        self.expect(change_addr)
 
     def test_sign_tx(self):
         account_map = "wsh(sortedmulti(1,[c7d0648a/48h/1h/0h/2h]tpubDEpefcgzY6ZyEV2uF4xcW2z8bZ3DNeWx9h2BcwcX973BHrmkQxJhpAXoSWZeHkmkiTtnUjfERsTDTVCcifW6po3PFR1JRjUUTJHvPpDqJhr/0/*,[12980eed/48h/1h/0h/2h]tpubDEkXGoQhYLFnYyzUGadtceUKbzVfXVorJEdo7c6VKJLHrULhpSVLC7fo89DDhjHmPvvNyrun2LTWH6FYmHh5VaQYPLEqLviVQKh45ufz8Ae/0/*,[3a52b5cd/48h/1h/0h/2h]tpubDFdbVee2Zna6eL9TkYBZDJVJ3RxGYWgChksXBRgw6y6PU1jWPTXUqag3CBMd6VDwok1hn5HZGvg6ujsTLXykrS3DwbxqCzEvWoT49gRJy7s/0/*,[f7d04090/48h/1h/0h/2h]tpubDF7FTuPECTePubPXNK73TYCzV3nRWaJnRwTXD28kh6Fz4LcaRzWwNtX153J7WeJFcQB2T6k9THd424Kmjs8Ps1FC1Xb81TXTxxbGZrLqQNp/0/*))#tatkmj5q"
@@ -99,58 +118,40 @@ def test_sign_tx(self):
         signed_psbt_b64 = "cHNidP8BAFICAAAAASqJ31Trzpdt/MCBc1rpqmJyTcrhHNgqYqmsoDzHoklrAQAAAAD+////AYcmAAAAAAAAFgAUVH5mMP/WhqzXEzUORHbh1WJ7TS4AAAAAAAEBKxAnAAAAAAAAIgAgW8ODIeZA3ep/uESxtEZmQlxl4Q0QWWbe4I7x3aHuEvAiAgI0eOoa6SLJeaxzFWRXvzgWElJmJgyZMSfbSZ7plUxF9kgwRQIhAKTtWurRx19SWBS0G50IkvEDqbdZG2Q0KuTPB3BRWUCoAiBBWAtAQdmL+uV7aMwcJIacsFtYzrGagkhf6ZfEySXPXgEBBYtRIQI0eOoa6SLJeaxzFWRXvzgWElJmJgyZMSfbSZ7plUxF9iECYYmlbj1NXorYlB1Ed7jOwa4nt+xwhePNaxnQW53o6lQhApaCK4Vcv04C6td57v3zGuHGrrVjXQEMKwKbbS8GHrkKIQLEV1INwWxsAYHEj/ElyUDHWQOxdbsfQzP2LT4IRZmWY1SuIgYCNHjqGukiyXmscxVkV784FhJSZiYMmTEn20me6ZVMRfYc99BAkDAAAIABAACAAAAAgAIAAIAAAAAABgAAACIGAmGJpW49TV6K2JQdRHe4zsGuJ7fscIXjzWsZ0Fud6OpUHDpStc0wAACAAQAAgAAAAIACAACAAAAAAAYAAAAiBgKWgiuFXL9OAurXee798xrhxq61Y10BDCsCm20vBh65ChwSmA7tMAAAgAEAAIAAAACAAgAAgAAAAAAGAAAAIgYCxFdSDcFsbAGBxI/xJclAx1kDsXW7H0Mz9i0+CEWZlmMcx9BkijAAAIABAACAAAAAgAIAAIAAAAAABgAAAAAA"
 
         self.child.sendline("send")
-        for _ in range(6):
-            self.child.readline()
-        res = str(self.child.read(50))
-        self.assertIn("Paste in your account map (AKA output record)", res)
+        self.expect("Paste in your account map (AKA output record")
+
         self.child.sendline(account_map)
-        self.child.readline()
-        res = str(self.child.read(70))
-        self.assertIn(
-            "Paste partially signed bitcoin transaction (PSBT) in base64 form", res
-        )
+        self.expect("Paste partially signed bitcoin transaction (PSBT) in base64 form")
+
         self.child.sendline(unsigned_psbt_b64)
-        self.child.readline()
-        res = str(self.child.read(75))
-        self.assertIn(
-            "Transaction appears to be a testnet transaction. Display as testnet?", res
-        )
+        self.expect("Display as testnet?")
+
         self.child.sendline("Y")
-        self.child.readline()
-        res = str(self.child.readline())
-        self.assertIn(
-            "PSBT sends 9,863 sats to tb1q23lxvv8l66r2e4cnx58ygahp6438knfwp8lapc with a fee of 137 sats (1.37% of spend)",
-            res,
+        self.expect(
+            "PSBT sends 9,863 sats to tb1q23lxvv8l66r2e4cnx58ygahp6438knfwp8lapc with a fee of 137 sats (1.37% of spend)"
         )
-        res = str(self.child.read(40))
-        self.assertIn("In Depth Transaction View?", res)
+        self.expect("In Depth Transaction View?")
+
         self.child.sendline("Y")
-        self.child.expect("DETAILED VIEW")
-        self.child.expect(
+        self.expect("DETAILED VIEW")
+        self.expect(
             "TXID: edbebb3fed50abcaecfffb993427becde623beac070fbcd822c36e2751cf0106"
         )
-        for _ in range(19):
-            self.child.readline()
-        res = str(self.child.read(30))
-        self.assertIn("Sign this transaction?", res)
+        self.expect("Sign this transaction?")
+
         self.child.sendline("Y")
-        self.child.readline()
-        res = str(self.child.read(40))
-        self.assertIn("Enter your full BIP39 seed phrase", res)
+        self.expect("Enter your full BIP39 seed phrase")
+
         self.child.sendline(seed_phrase)
-        self.child.readline()
-        res = str(self.child.read(50))
-        self.assertIn("Use a passphrase (advanced users only)?", res)
+        self.expect("Use a passphrase (advanced users only)?")
+
         self.child.sendline("N")
-        self.child.expect("Signed PSBT to broadcast")
-        self.child.readline()
-        self.child.readline()
-        res = str(self.child.readline())
-        self.assertIn(signed_psbt_b64, res)
+        self.expect("Signed PSBT to broadcast")
+
+        self.expect(signed_psbt_b64)
 
     def test_fail(self):
         # This has to take some seconds to fail
-        # TODO: find a way to make this optional (default to no because slow)
-        mw = pexpect.spawn("python3 multiwallet.py", timeout=2)
+        mw = pexpect.spawn("python3 multiwallet.py", timeout=1)
         with self.assertRaises(pexpect.exceptions.TIMEOUT):
             mw.expect("this text should not match")
diff --git a/test_singlesweep.py b/test_singlesweep.py
index c53f544..7619e44 100644
--- a/test_singlesweep.py
+++ b/test_singlesweep.py
@@ -6,18 +6,46 @@
 
 
 class SinglesweepTest(unittest.TestCase):
+    def expect(self, text):
+        """
+        Expect a string of bytes one at a time (not waiting on a newline)
+        """
+        buffer = ""
+        while True:
+
+            try:
+                # This will error out at the end of the buffer
+                latest_char = self.child.read(1)
+            except Exception as e:
+                print("buffer", buffer)
+                raise Exception(f"Failed to find text `{text}`in buffer. Error: {e}")
+
+            try:
+                latest_char = latest_char.decode()
+                if latest_char not in ("\n", "\r"):
+                    buffer += latest_char
+            except UnicodeDecodeError:
+                # Handle non-unicode char edge-case (bitcoin symbol)
+                buffer += str(latest_char)
+
+            if text in buffer:
+                return True
+
+        # this line should never be reached, the script would timeout first
+        assert f"`{text}` not in buffer: {buffer}"
+
     def setUp(self):
         self.child = pexpect.spawn("python3 singlesweep.py", timeout=2)
-        self.child.expect(
+        self.expect(
             "Welcome to singlesweep, a stateless single sig sweeper that works with WIF and PSBTs."
         )
 
     def test_debug(self):
         self.child.sendline("debug")
-        self.child.expect("buidl Version: ")
-        self.child.expect("Python Version: ")
-        self.child.expect("Platform: ")
-        self.child.expect("libsecp256k1 Configured: ")
+        self.expect("buidl Version: ")
+        self.expect("Python Version: ")
+        self.expect("Platform: ")
+        self.expect("libsecp256k1 Configured: ")
 
     def test_send_compressed(self):
         # This isn't strictly neccesary, just shows how this was generated
@@ -34,38 +62,30 @@ def test_send_compressed(self):
         )
 
         self.child.sendline("sweep")
-        for _ in range(5):
-            self.child.readline()
-        res = str(self.child.read(70))
-        self.assertIn("Enter WIF (Wallet Import Format) to use for signing:", res)
+        self.expect("Enter WIF (Wallet Import Format) to use for signing:")
+
         self.child.sendline("cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuh9HqjiLNWDVQudB7k4E")
-        self.child.expect(
+        self.expect(
             "Will attempt to spend from TESTNET mxgA6BsDLcv4vooLx4j6MfHQRihbrdwV5P"
         )
-        self.child.readline()
-        res = str(self.child.read(70))
-        self.assertIn(
-            "Paste partially signed bitcoin transaction (PSBT) in base64 form", res
-        )
+        self.expect("Paste partially signed bitcoin transaction (PSBT) in base64 form")
+
         psbt_to_sign = "cHNidP8BAFUCAAAAAVRZh97dheVJzHkcaznyZCtSunoNJgnNGBRKGYw5nBSQAQAAAAD9////ASCFAQAAAAAAGXapFJ+aer1gDAyqA5g6d8jD344GLLL6iKxZiR4AAAEA4gIAAAAAAQEy/IizvbchxG0F6yLb/g0qEa9HidaAzlDzGCUMNgwZTQAAAAAA/v///wKEOaMAAAAAABepFOpylCCZWu7JekQ9p98RPeFn3kRoh6CGAQAAAAAAGXapFLw3unG6dBaKPCHEL+A8dYsff8aRiKwCRzBEAiBanqsb6aKeGstvedoheUCnr7buvdOHz58/J803NfsOkAIgOIpcQ+OGZEzFo7E3FBvUHagLZJLik8vf9KqnfVwfn9MBIQO3M5Kw2cHk3i3s1FpZK69B/oUOubZhv6e/GU7n6RVAeViJHgAAAA=="
         self.child.sendline(psbt_to_sign)
-        self.child.readline()
-        res = str(self.child.readline())
-        want = "PSBT sends 99,616 sats to mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB with an UNVERIFIED fee of 384 sats (0.38% of spend)"
-        self.assertIn(want, res)
-        res = str(self.child.read(40))
-        self.assertIn("In Depth Transaction View? [Y/n]", res)
+        self.expect(
+            "PSBT sends 99,616 sats to mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB with an UNVERIFIED fee of 384 sats (0.38% of spend)"
+        )
+        self.expect("In Depth Transaction View? [Y/n]")
+
         self.child.sendline("Y")
-        self.child.expect("DETAILED VIEW")
-        for _ in range(21):
-            self.child.readline()
-        res = str(self.child.read(35))
-        self.assertIn("Sign this transaction?", res)
+        self.expect("DETAILED VIEW")
+        self.expect("Sign this transaction?")
+
         self.child.sendline("Y")
-        self.child.expect(
+        self.expect(
             "SIGNED TX 0dfc0c3b8e0e87b6321a75fca542c22f792b2d6f519720e0a974976c646b7d5e"
         )
-        self.child.expect(
+        self.expect(
             "0200000001545987dedd85e549cc791c6b39f2642b52ba7a0d2609cd18144a198c399c1490010000006a473044022076ce7079425632ca3d355d33c9f8d5152bdfef87e7ef4a8be3792f3cbc4c7f4702201da9fd053b42c4ea2b57717d8b4995caf6f3d47cf7572f54122f158c208c4d3c012102f64b30341c33fb908144acb898781e1cf011bae3e44489864a6c621ded2a29aafdffffff0120850100000000001976a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac59891e00"
         )
 
@@ -84,44 +104,34 @@ def test_send_uncompressed(self):
         )
 
         self.child.sendline("sweep")
-        for _ in range(5):
-            self.child.readline()
-        res = str(self.child.read(70))
-        self.assertIn("Enter WIF (Wallet Import Format) to use for signing:", res)
+        self.expect("Enter WIF (Wallet Import Format) to use for signing:")
+
         self.child.sendline("91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4nM1C3RmiaMW6WFGmDS")
-        self.child.expect(
+        self.expect(
             "Will attempt to spend from TESTNET mzJtwV9LL6B3Nvm1uc1Z5NK3mqqaZyn9w1"
         )
-        self.child.readline()
-        res = str(self.child.read(70))
-        self.assertIn(
-            "Paste partially signed bitcoin transaction (PSBT) in base64 form", res
-        )
+        self.expect("Paste partially signed bitcoin transaction (PSBT) in base64 form")
         psbt_to_sign = "cHNidP8BAFUCAAAAAaASEHE91UJrrmU5FMjXIVUV5HF91EGzcaktfooEUPBFAAAAAAD9////AWPhFwAAAAAAGXapFJ+aer1gDAyqA5g6d8jD344GLLL6iKxniR4AAAEA4gIAAAAAAQH96ccGxhmgYfsrP9xnIUl2WJxnE+Jz2iAH08QAkPiSiQAAAAAA/v///wLj4hcAAAAAABl2qRTOIpkaGEnqK3MB5zwY6WWk/ZKiRoisAWO7XQAAAAAXqRT2kti1/KAVtU90LS4zl1LNGa3NtocCRzBEAiAnsPi908ar1ROFyTWV4TlqlKHijNRbOuolJILCG2G6ywIgCPZLYkWebvcTOztJj3I+D6CX/y9DCZRRhrD9QJtdR80BIQPLHa2FJlrG7KzxKA6ZVJfJ2P3xGp/88a65XIkCNK6Xk1iJHgAAAA=="
         self.child.sendline(psbt_to_sign)
-        self.child.readline()
-        res = str(self.child.readline())
-        want = "PSBT sends 1,565,027 sats to mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB with an UNVERIFIED fee of 384 sats (0.02% of spend)"
-        self.assertIn(want, res)
-        res = str(self.child.read(40))
-        self.assertIn("In Depth Transaction View?", res)
+        self.expect(
+            "PSBT sends 1,565,027 sats to mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB with an UNVERIFIED fee of 384 sats (0.02% of spend)"
+        )
+        self.expect("In Depth Transaction View?")
+
         self.child.sendline("Y")
-        self.child.expect("DETAILED VIEW")
-        for _ in range(21):
-            self.child.readline()
-        res = str(self.child.read(35))
-        self.assertIn("Sign this transaction?", res)
+        self.expect("DETAILED VIEW")
+        self.expect("Sign this transaction?")
+
         self.child.sendline("Y")
-        self.child.expect(
+        self.expect(
             "SIGNED TX f3271bbac2b66d83379de855a79cead9d0e5210b857bee5c22462635033861c4"
         )
-        self.child.expect(
+        self.expect(
             "0200000001a01210713dd5426bae653914c8d7215515e4717dd441b371a92d7e8a0450f045000000008b4830450221008123f3ce37457a8c61709d873bddf3fc93e46f684749956571d59acbd00087c002202346068137f144df11d92fa185640c848dd89c22552803b502e34be56e9da6de014104f64b30341c33fb908144acb898781e1cf011bae3e44489864a6c621ded2a29aaee264a64a924c505d1e66bc7308b2d87806813ad203725d7a9548c9d79017d36fdffffff0163e11700000000001976a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac67891e00"
         )
 
     def test_fail(self):
         # This has to take some seconds to fail
-        # TODO: find a way to make this optional (default to no because slow)
-        mw = pexpect.spawn("python3 singlesweep.py", timeout=2)
+        mw = pexpect.spawn("python3 singlesweep.py", timeout=1)
         with self.assertRaises(pexpect.exceptions.TIMEOUT):
             mw.expect("this text should not match")