Merge #11923: Wallet : remove unused fNoncriticalErrors variable from CWalletDB:...
[bitcoinplatinum.git] / test / functional / example_test.py
blob12be685ecf4232a83ebd598f35579d82468236cd
1 #!/usr/bin/env python3
2 # Copyright (c) 2017 The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """An example functional test
7 The module-level docstring should include a high-level description of
8 what the test is doing. It's the first thing people see when they open
9 the file and should give the reader information about *what* the test
10 is testing and *how* it's being tested
11 """
12 # Imports should be in PEP8 ordering (std library first, then third party
13 # libraries then local imports).
14 from collections import defaultdict
16 # Avoid wildcard * imports if possible
17 from test_framework.blocktools import (create_block, create_coinbase)
18 from test_framework.mininode import (
19 CInv,
20 P2PInterface,
21 mininode_lock,
22 msg_block,
23 msg_getdata,
24 network_thread_join,
25 network_thread_start,
27 from test_framework.test_framework import BitcoinTestFramework
28 from test_framework.util import (
29 assert_equal,
30 connect_nodes,
31 wait_until,
34 # P2PInterface is a class containing callbacks to be executed when a P2P
35 # message is received from the node-under-test. Subclass P2PInterface and
36 # override the on_*() methods if you need custom behaviour.
37 class BaseNode(P2PInterface):
38 def __init__(self):
39 """Initialize the P2PInterface
41 Used to inialize custom properties for the Node that aren't
42 included by default in the base class. Be aware that the P2PInterface
43 base class already stores a counter for each P2P message type and the
44 last received message of each type, which should be sufficient for the
45 needs of most tests.
47 Call super().__init__() first for standard initialization and then
48 initialize custom properties."""
49 super().__init__()
50 # Stores a dictionary of all blocks received
51 self.block_receive_map = defaultdict(int)
53 def on_block(self, message):
54 """Override the standard on_block callback
56 Store the hash of a received block in the dictionary."""
57 message.block.calc_sha256()
58 self.block_receive_map[message.block.sha256] += 1
60 def on_inv(self, message):
61 """Override the standard on_inv callback"""
62 pass
64 def custom_function():
65 """Do some custom behaviour
67 If this function is more generally useful for other tests, consider
68 moving it to a module in test_framework."""
69 # self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
70 pass
72 class ExampleTest(BitcoinTestFramework):
73 # Each functional test is a subclass of the BitcoinTestFramework class.
75 # Override the set_test_params(), add_options(), setup_chain(), setup_network()
76 # and setup_nodes() methods to customize the test setup as required.
78 def set_test_params(self):
79 """Override test parameters for your individual test.
81 This method must be overridden and num_nodes must be exlicitly set."""
82 self.setup_clean_chain = True
83 self.num_nodes = 3
84 # Use self.extra_args to change command-line arguments for the nodes
85 self.extra_args = [[], ["-logips"], []]
87 # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test()
89 # Use add_options() to add specific command-line options for your test.
90 # In practice this is not used very much, since the tests are mostly written
91 # to be run in automated environments without command-line options.
92 # def add_options()
93 # pass
95 # Use setup_chain() to customize the node data directories. In practice
96 # this is not used very much since the default behaviour is almost always
97 # fine
98 # def setup_chain():
99 # pass
101 def setup_network(self):
102 """Setup the test network topology
104 Often you won't need to override this, since the standard network topology
105 (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests.
107 If you do override this method, remember to start the nodes, assign
108 them to self.nodes, connect them and then sync."""
110 self.setup_nodes()
112 # In this test, we're not connecting node2 to node0 or node1. Calls to
113 # sync_all() should not include node2, since we're not expecting it to
114 # sync.
115 connect_nodes(self.nodes[0], 1)
116 self.sync_all([self.nodes[0:1]])
118 # Use setup_nodes() to customize the node start behaviour (for example if
119 # you don't want to start all nodes at the start of the test).
120 # def setup_nodes():
121 # pass
123 def custom_method(self):
124 """Do some custom behaviour for this test
126 Define it in a method here because you're going to use it repeatedly.
127 If you think it's useful in general, consider moving it to the base
128 BitcoinTestFramework class so other tests can use it."""
130 self.log.info("Running custom_method")
132 def run_test(self):
133 """Main test logic"""
135 # Create P2P connections to two of the nodes
136 self.nodes[0].add_p2p_connection(BaseNode())
138 # Start up network handling in another thread. This needs to be called
139 # after the P2P connections have been created.
140 network_thread_start()
141 # wait_for_verack ensures that the P2P connection is fully up.
142 self.nodes[0].p2p.wait_for_verack()
144 # Generating a block on one of the nodes will get us out of IBD
145 blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
146 self.sync_all([self.nodes[0:1]])
148 # Notice above how we called an RPC by calling a method with the same
149 # name on the node object. Notice also how we used a keyword argument
150 # to specify a named RPC argument. Neither of those are defined on the
151 # node object. Instead there's some __getattr__() magic going on under
152 # the covers to dispatch unrecognised attribute calls to the RPC
153 # interface.
155 # Logs are nice. Do plenty of them. They can be used in place of comments for
156 # breaking the test into sub-sections.
157 self.log.info("Starting test!")
159 self.log.info("Calling a custom function")
160 custom_function()
162 self.log.info("Calling a custom method")
163 self.custom_method()
165 self.log.info("Create some blocks")
166 self.tip = int(self.nodes[0].getbestblockhash(), 16)
167 self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
169 height = 1
171 for i in range(10):
172 # Use the mininode and blocktools functionality to manually build a block
173 # Calling the generate() rpc is easier, but this allows us to exactly
174 # control the blocks and transactions.
175 block = create_block(self.tip, create_coinbase(height), self.block_time)
176 block.solve()
177 block_message = msg_block(block)
178 # Send message is used to send a P2P message to the node over our P2PInterface
179 self.nodes[0].p2p.send_message(block_message)
180 self.tip = block.sha256
181 blocks.append(self.tip)
182 self.block_time += 1
183 height += 1
185 self.log.info("Wait for node1 to reach current tip (height 11) using RPC")
186 self.nodes[1].waitforblockheight(11)
188 self.log.info("Connect node2 and node1")
189 connect_nodes(self.nodes[1], 2)
191 self.log.info("Add P2P connection to node2")
192 # We can't add additional P2P connections once the network thread has started. Disconnect the connection
193 # to node0, wait for the network thread to terminate, then connect to node2. This is specific to
194 # the current implementation of the network thread and may be improved in future.
195 self.nodes[0].disconnect_p2ps()
196 network_thread_join()
198 self.nodes[2].add_p2p_connection(BaseNode())
199 network_thread_start()
200 self.nodes[2].p2p.wait_for_verack()
202 self.log.info("Wait for node2 reach current tip. Test that it has propagated all the blocks to us")
204 getdata_request = msg_getdata()
205 for block in blocks:
206 getdata_request.inv.append(CInv(2, block))
207 self.nodes[2].p2p.send_message(getdata_request)
209 # wait_until() will loop until a predicate condition is met. Use it to test properties of the
210 # P2PInterface objects.
211 wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock)
213 self.log.info("Check that each block was received only once")
214 # The network thread uses a global lock on data access to the P2PConnection objects when sending and receiving
215 # messages. The test thread should acquire the global lock before accessing any P2PConnection data to avoid locking
216 # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate.
217 with mininode_lock:
218 for block in self.nodes[2].p2p.block_receive_map.values():
219 assert_equal(block, 1)
221 if __name__ == '__main__':
222 ExampleTest().main()