scripted-diff: Use the C++11 keyword nullptr to denote the pointer literal instead...
[bitcoinplatinum.git] / test / functional / example_test.py
blob1ba5f756cd4a05cd4f7388ffad125b0f899bceef
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 NetworkThread,
21 NodeConn,
22 NodeConnCB,
23 mininode_lock,
24 msg_block,
25 msg_getdata,
26 wait_until,
28 from test_framework.test_framework import BitcoinTestFramework
29 from test_framework.util import (
30 assert_equal,
31 connect_nodes,
32 p2p_port,
35 # NodeConnCB is a class containing callbacks to be executed when a P2P
36 # message is received from the node-under-test. Subclass NodeConnCB and
37 # override the on_*() methods if you need custom behaviour.
38 class BaseNode(NodeConnCB):
39 def __init__(self):
40 """Initialize the NodeConnCB
42 Used to inialize custom properties for the Node that aren't
43 included by default in the base class. Be aware that the NodeConnCB
44 base class already stores a counter for each P2P message type and the
45 last received message of each type, which should be sufficient for the
46 needs of most tests.
48 Call super().__init__() first for standard initialization and then
49 initialize custom properties."""
50 super().__init__()
51 # Stores a dictionary of all blocks received
52 self.block_receive_map = defaultdict(int)
54 def on_block(self, conn, message):
55 """Override the standard on_block callback
57 Store the hash of a received block in the dictionary."""
58 message.block.calc_sha256()
59 self.block_receive_map[message.block.sha256] += 1
61 def custom_function():
62 """Do some custom behaviour
64 If this function is more generally useful for other tests, consider
65 moving it to a module in test_framework."""
66 # self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
67 pass
69 class ExampleTest(BitcoinTestFramework):
70 # Each functional test is a subclass of the BitcoinTestFramework class.
72 # Override the __init__(), add_options(), setup_chain(), setup_network()
73 # and setup_nodes() methods to customize the test setup as required.
75 def __init__(self):
76 """Initialize the test
78 Call super().__init__() first, and then override any test parameters
79 for your individual test."""
80 super().__init__()
81 self.setup_clean_chain = True
82 self.num_nodes = 3
83 # Use self.extra_args to change command-line arguments for the nodes
84 self.extra_args = [[], ["-logips"], []]
86 # self.log.info("I've finished __init__") # Oops! Can't run self.log before run_test()
88 # Use add_options() to add specific command-line options for your test.
89 # In practice this is not used very much, since the tests are mostly written
90 # to be run in automated environments without command-line options.
91 # def add_options()
92 # pass
94 # Use setup_chain() to customize the node data directories. In practice
95 # this is not used very much since the default behaviour is almost always
96 # fine
97 # def setup_chain():
98 # pass
100 def setup_network(self):
101 """Setup the test network topology
103 Often you won't need to override this, since the standard network topology
104 (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests.
106 If you do override this method, remember to start the nodes, assign
107 them to self.nodes, connect them and then sync."""
109 self.setup_nodes()
111 # In this test, we're not connecting node2 to node0 or node1. Calls to
112 # sync_all() should not include node2, since we're not expecting it to
113 # sync.
114 connect_nodes(self.nodes[0], 1)
115 self.sync_all([self.nodes[0:1]])
117 # Use setup_nodes() to customize the node start behaviour (for example if
118 # you don't want to start all nodes at the start of the test).
119 # def setup_nodes():
120 # pass
122 def custom_method(self):
123 """Do some custom behaviour for this test
125 Define it in a method here because you're going to use it repeatedly.
126 If you think it's useful in general, consider moving it to the base
127 BitcoinTestFramework class so other tests can use it."""
129 self.log.info("Running custom_method")
131 def run_test(self):
132 """Main test logic"""
134 # Create a P2P connection to one of the nodes
135 node0 = BaseNode()
136 connections = []
137 connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
138 node0.add_connection(connections[0])
140 # Start up network handling in another thread. This needs to be called
141 # after the P2P connections have been created.
142 NetworkThread().start()
143 # wait_for_verack ensures that the P2P connection is fully up.
144 node0.wait_for_verack()
146 # Generating a block on one of the nodes will get us out of IBD
147 blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
148 self.sync_all([self.nodes[0:1]])
150 # Notice above how we called an RPC by calling a method with the same
151 # name on the node object. Notice also how we used a keyword argument
152 # to specify a named RPC argument. Neither of those are defined on the
153 # node object. Instead there's some __getattr__() magic going on under
154 # the covers to dispatch unrecognised attribute calls to the RPC
155 # interface.
157 # Logs are nice. Do plenty of them. They can be used in place of comments for
158 # breaking the test into sub-sections.
159 self.log.info("Starting test!")
161 self.log.info("Calling a custom function")
162 custom_function()
164 self.log.info("Calling a custom method")
165 self.custom_method()
167 self.log.info("Create some blocks")
168 self.tip = int(self.nodes[0].getbestblockhash(), 16)
169 self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
171 height = 1
173 for i in range(10):
174 # Use the mininode and blocktools functionality to manually build a block
175 # Calling the generate() rpc is easier, but this allows us to exactly
176 # control the blocks and transactions.
177 block = create_block(self.tip, create_coinbase(height), self.block_time)
178 block.solve()
179 block_message = msg_block(block)
180 # Send message is used to send a P2P message to the node over our NodeConn connection
181 node0.send_message(block_message)
182 self.tip = block.sha256
183 blocks.append(self.tip)
184 self.block_time += 1
185 height += 1
187 self.log.info("Wait for node1 to reach current tip (height 11) using RPC")
188 self.nodes[1].waitforblockheight(11)
190 self.log.info("Connect node2 and node1")
191 connect_nodes(self.nodes[1], 2)
193 self.log.info("Add P2P connection to node2")
194 node2 = BaseNode()
195 connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
196 node2.add_connection(connections[1])
197 node2.wait_for_verack()
199 self.log.info("Wait for node2 reach current tip. Test that it has propogated all the blocks to us")
201 for block in blocks:
202 getdata_request = msg_getdata()
203 getdata_request.inv.append(CInv(2, block))
204 node2.send_message(getdata_request)
206 # wait_until() will loop until a predicate condition is met. Use it to test properties of the
207 # NodeConnCB objects.
208 assert wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5)
210 self.log.info("Check that each block was received only once")
211 # The network thread uses a global lock on data access to the NodeConn objects when sending and receiving
212 # messages. The test thread should acquire the global lock before accessing any NodeConn data to avoid locking
213 # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate.
214 with mininode_lock:
215 for block in node2.block_receive_map.values():
216 assert_equal(block, 1)
218 if __name__ == '__main__':
219 ExampleTest().main()