Skip to content

Conversation

slmtpz
Copy link
Contributor

@slmtpz slmtpz commented Aug 17, 2020

Replace global (from test_framework/util.py) wait_until() usages with the ones provided by BitcoinTestFramework and P2PInterface classes.

The motivation behind this change is that the util.wait_until() expects a timeout, timeout_factor and lock and it is not aware of the context of the test framework. BitcoinTestFramework offers a wait_until() which has an understandable amount of default timeout and a shared timeout_factor. Moreover, on top of these, mininode.wait_until() also has a shared lock.

closes #19080

@DrahtBot DrahtBot added the Tests label Aug 17, 2020
@maflcko
Copy link
Member

maflcko commented Aug 18, 2020

Very nice. Concept ACK

@practicalswift
Copy link
Contributor

Nice first-time contribution! Warm welcome as a contributor @slmtpz :)

Concept ACK

@slmtpz
Copy link
Contributor Author

slmtpz commented Aug 18, 2020

Nice first-time contribution! Warm welcome as a contributor @slmtpz :)

Concept ACK

Thank you, looking forward to more contributions in future!

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 20, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

Copy link
Member

@glozow glozow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK, welcome! 😊 this is awesome!

I complain about this pretty often 😅 The util wait_until function doesn't have any context from the TestFramework instance (i.e. timeout and timeout_factor). Sometimes when it's used, the test writer forgets to pass in the mininode_lock which is even worse. I think it would be a good idea to add a comment to the wait_until function in test_framework.util that recommends using something else, because it's almost never the best option - this is just my opinion though. (Btw, I recommend adding something along these lines to the PR description to explain what motivates these changes).

We actually have more options than just TestFramework wait_until. There are a few places where one of the mininode helper functions (wait_for_disconnect, wait_for_broadcast, etc) or the mininode wait_until would be more appropriate.

There seem to be some changes that are unrelated to changing which wait_until is used. I didn't look into them too closely, but could you give an explanation and/or put them in a separate PR?

Also a style nit: there's a few places where you're refactoring the imports in addition to removing wait_until, which I don't think is the style convention and makes the diff larger than it needs to be.


def send_await_disconnect(self, message, timeout=30):
"""Sends a message to the node and wait for disconnect.

This is used when we want to send a message into the node that we expect
will get us disconnected, eg an invalid block."""
self.send_message(message)
wait_until(lambda: not self.is_connected, timeout=timeout, lock=mininode_lock)
self.wait_until(lambda: not self.is_connected, timeout=timeout, check_connected=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, is there a reason for removing mininode_lock and adding check_connected=False?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, wait_for_disconnect would be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used wait_for_disconnect instead, thanks!

@@ -174,7 +171,7 @@ def check_last_headers_announcement(self, headers):
"""Test whether the last headers announcements received are right.
Headers may be announced across more than one message."""
test_function = lambda: (len(self.recent_headers_announced) >= len(headers))
wait_until(test_function, timeout=60, lock=mininode_lock)
self.wait_until(test_function)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you removing the timeout and lock here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class extends P2PInterface not BitcoinTestFramework. mininode one already has a lock. As for timeout, it already has a default value of 60.

@@ -186,7 +183,7 @@ def check_last_inv_announcement(self, inv):
inv should be a list of block hashes."""

test_function = lambda: self.block_announced
wait_until(test_function, timeout=60, lock=mininode_lock)
self.wait_until(test_function)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class extends P2PInterface not BitcoinTestFramework. mininode one already has a lock. As for timeout, it already has a default value of 60.

@@ -294,7 +294,7 @@ def test_compactblock_construction(self, test_node, use_witness_address=True):
block.rehash()

# Wait until the block was announced (via compact blocks)
wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock)
self.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is one of the goals of this PR, but in this situation I think it's best to use test_node.wait_until().

Same with the rest of the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was inclined to use the one from BitcoinTestFramework since I thought it would be good to keep consistency. However, in this case, since we are waiting for a change in test_node, using that one makes more sense, did I get it right? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

@@ -33,7 +33,7 @@ def run_test(self):
time.sleep(1.1)

# Can take a few seconds due to transaction trickling
wait_until(lambda: node.p2p.tx_invs_received[txid] >= 1, lock=mininode_lock)
self.wait_until(lambda: node.p2p.tx_invs_received[txid] >= 1, lock=mininode_lock)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, wait_for_broadcast(txid) would be more appropriate

(txid needs to not be converted to int though)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks cleaner now! Please have a look.

@@ -64,7 +64,7 @@ def run_test(self):
# Transaction should be rebroadcast approximately 24 hours in the future,
# but can range from 12-36. So bump 36 hours to be sure.
node.setmocktime(now + 36 * 60 * 60)
wait_until(lambda: node.p2ps[1].tx_invs_received[txid] >= 1, lock=mininode_lock)
self.wait_until(lambda: node.p2ps[1].tx_invs_received[txid] >= 1, lock=mininode_lock)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@slmtpz slmtpz force-pushed the master branch 4 times, most recently from 662636e to c132bc3 Compare August 25, 2020 19:32
@slmtpz
Copy link
Contributor Author

slmtpz commented Aug 25, 2020

Concept ACK, welcome! 😊 this is awesome!

I complain about this pretty often 😅 The util wait_until function doesn't have any context from the TestFramework instance (i.e. timeout and timeout_factor). Sometimes when it's used, the test writer forgets to pass in the mininode_lock which is even worse. I think it would be a good idea to add a comment to the wait_until function in test_framework.util that recommends using something else, because it's almost never the best option - this is just my opinion though. (Btw, I recommend adding something along these lines to the PR description to explain what motivates these changes).

We actually have more options than just TestFramework wait_until. There are a few places where one of the mininode helper functions (wait_for_disconnect, wait_for_broadcast, etc) or the mininode wait_until would be more appropriate.

There seem to be some changes that are unrelated to changing which wait_until is used. I didn't look into them too closely, but could you give an explanation and/or put them in a separate PR?

Also a style nit: there's a few places where you're refactoring the imports in addition to removing wait_until, which I don't think is the style convention and makes the diff larger than it needs to be.

Thanks for the thorough review and double thanks for your suggestions! Going deeper, things had started to build up in my mind.
Rebase + force pushed the changes you suggested. As for your other proposal to add a comment in util.wait_until(), please look at this second commit.
PR description is also updated. Should I update commit body as well (after your approval of the motivation for this change stated in the PR description) ?

Copy link
Contributor

@kallewoof kallewoof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big concept ACK: much cleaner!

utACK 0a2d507

One thing that tripped me up when reviewing is that there are two separate wait_until methods, one (in P2PInterface) which has a default lock (mininode_lock) and one (in BitcoinTestFramework) which doesn't. This is why you see the lock=mininode_lock in a few places, while it's removed in a bunch of others. (Check super class.)

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK

8823fd6c702f3c7c97218b1dbeda2b9386873d69

@@ -91,14 +90,14 @@ def run_test(self):

# Generating one block guarantees that we'll get out of IBD
node.generatetoaddress(1, node_deterministic_address)
wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock)
self.wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock)
self.wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10)

why the lock?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class of this method inherits from BitcoinTestFramework which does not have a default lock.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why is the lock needed? Why does it need to be taken here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I frankly don't know. It was there before, so I didn't touch it.

slmtpz added 2 commits August 26, 2020 18:01
Replace "wait_until()" usage from utils, with the ones from BitcoinTestFramework and P2PInterface.
closes bitcoin#19080
@slmtpz slmtpz requested a review from maflcko August 26, 2020 16:08
Copy link
Contributor

@kallewoof kallewoof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK d841301

@maflcko
Copy link
Member

maflcko commented Aug 27, 2020

Thanks for keeping this updated and addressing all the feedback!

ACK d841301 🦆

Show signature and timestamp

Signature:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

ACK d841301010914203fb5ef02627c76fad99cb11f1 🦆
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
pUjVKAwAzGdH57AIPkBd3pQiCIm0PMYONNZEur6hn6VVGnLOatyGbLlTQLaw/kwu
VZl6jutSgIusoKNUkjJLgPV2yiQF3PN9xrhS5IwGfGXYX9nvdwy4T/dhmLv6XUuE
HO0+pM7fYE6XoyvK+YPV60uIkb3cgX8hVOU8ACd7GuIESkGiLnxN4zYxZN2Zyrvo
yPUcOAKGXXJom6wzXXUQUZSp9BE5HJexWydui4iduwwkX2n+8yJKOYQ0Hv/kzqo1
uD2gB+GmVUzpfNs3RUkLot2gtl0yK5bqYAVmyCfNXTppRD1yt1JnvxWooFeeW02t
kL5JRg6aFy/PkM+tfTU/uZ3kEuSI0STHYJu5O0Ev9nG2cWKHbERP+LLIIiy0crns
UyyQ9rSaKjMucDlNfbXEg95zf2pRxE9hvqFwBQQT5VC06Pfn6k4Xmi5UfpwRlTSa
4uSSz/dtO5FMvbST5NCXtTOutkFmDmkLyHGOtynLs0Px7GrHtyhn0mL9OnnLbeqV
/mQJZu0x
=HU8g
-----END PGP SIGNATURE-----

Timestamp of file with hash 8841ab10d7ee7a298b7cd8d05a44bfb9c3aaaa6e2c48b70e1d0adeb3afe2f62e -

@maflcko maflcko merged commit 28f4e53 into bitcoin:master Aug 27, 2020
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Aug 28, 2020
…e the one from utils

d841301 test: Add docstring to wait_until() in util.py to warn about its usage (Seleme Topuz)
1343c86 test: Update wait_until usage in tests not to use the one from utils (Seleme Topuz)

Pull request description:

  Replace global (from [test_framework/util.py](https://github.com/bitcoin/bitcoin/blob/master/test/functional/test_framework/util.py#L228)) `wait_until()` usages with the ones provided by `BitcoinTestFramework` and `P2PInterface` classes.

  The motivation behind this change is that the `util.wait_until()` expects a timeout, timeout_factor and lock and it is not aware of the context of the test framework. `BitcoinTestFramework` offers a `wait_until()` which has an understandable amount of default `timeout` and a shared `timeout_factor`. Moreover, on top of these, `mininode.wait_until()` also has a shared lock.

  closes bitcoin#19080

ACKs for top commit:
  MarcoFalke:
    ACK d841301 🦆
  kallewoof:
    utACK d841301

Tree-SHA512: 81604f4cfa87fed98071a80e4afe940b3897fe65cf680a69619a93e97d45f25b313c12227de7040e19517fa9c003291b232f1b40b2567aba0148f22c23c47a88
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Sep 16, 2021
Summary:
Using the global wait_until makes it impossible to adjust the timeout based on the hardware the test is running on.

> test: Update wait_until usage in tests not to use the one from utils
>
> Replace "wait_until()" usage from utils, with the ones from BitcoinTestFramework and P2PInterface.
> closes #19080

> test: Add docstring to wait_until() in util.py to warn about its usage

This is a backport of [[bitcoin/bitcoin#19752 | core#19752]]

Test Plan: `ninja check-functional-extended`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D10128
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

test: Replace gobal wait_until with mininode.wait_until
6 participants