github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/integration/sawtooth_integration/tests/test_two_families.py (about) 1 # Copyright 2017 Intel Corporation 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ------------------------------------------------------------------------------ 15 16 # pylint: disable=attribute-defined-outside-init 17 18 import unittest 19 import logging 20 import operator 21 import subprocess 22 import shlex 23 import urllib.request 24 import urllib.error 25 import json 26 from base64 import b64decode 27 28 import cbor 29 30 from sawtooth_intkey.intkey_message_factory import IntkeyMessageFactory 31 from sawtooth_integration.tests.integration_tools import wait_for_rest_apis 32 33 34 LOGGER = logging.getLogger(__name__) 35 LOGGER.setLevel(logging.INFO) 36 37 38 INTKEY_PREFIX = '1cf126' 39 XO_PREFIX = '5b7349' 40 WAIT = 300 41 42 43 class TestTwoFamilies(unittest.TestCase): 44 45 @classmethod 46 def setUpClass(cls): 47 wait_for_rest_apis(['rest-api:8008']) 48 49 def test_two_families(self): 50 ''' 51 After starting a validator with both intkey and xo 52 transaction processors and initializing xo, verify that 53 state is empty. Next, send the following pairs of commands, 54 verifying that the state is as it should be after each: 55 56 1. Send a batch of intkey 'set' txns and create an xo game. 57 58 2. Send a batch of valid intkey 'inc'/'dec' txns and take an xo space. 59 60 3. Send an invalid batch of intkey 'inc'/'dec' txns (invalid because 61 they target names that haven't been set) and take the same xo space. 62 63 4. Send more valid intkey txns and take a new xo space. 64 65 5. Send the same intkey 'set' txns (which are now invalid) and 66 create the same xo game (which has already been created). 67 68 6. Send more valid intkey txns and take a new xo space. 69 70 Besides verifying that the xo and intkey commands act as expected, 71 verify that there is nothing in the state that isn't xo or intkey. 72 ''' 73 74 self.intkey_verifier = IntkeyTestVerifier() 75 self.xo_verifier = XoTestVerifier() 76 77 _send_xo_cmd('sawtooth keygen') 78 79 self.verify_empty_state() 80 81 commands = zip( 82 self.intkey_verifier.intkey_cmds, 83 self.xo_verifier.xo_cmds) 84 85 how_many_updates = 0 86 87 for intkey_cmd, xo_cmd in commands: 88 _send_intkey_cmd(intkey_cmd) 89 _send_xo_cmd('{} --url {} --wait {}'.format( 90 xo_cmd, 91 'http://rest-api:8008', 92 WAIT)) 93 94 if intkey_cmd == self.intkey_verifier.valid_txns: 95 how_many_updates += 1 96 97 self.verify_state_after_n_updates(how_many_updates) 98 99 def verify_empty_state(self): 100 LOGGER.debug('Verifying empty state') 101 102 self.assertEqual( 103 [], 104 _get_intkey_state(), 105 'Expected intkey state to be empty') 106 107 self.assertEqual( 108 [], 109 _get_xo_state(), 110 'Expected xo state to be empty') 111 112 def verify_state_after_n_updates(self, num): 113 LOGGER.debug('Verifying state after %s updates', num) 114 115 intkey_state = _get_intkey_data() 116 LOGGER.info('Current intkey state: %s', intkey_state) 117 xo_data = _get_xo_data() 118 LOGGER.info('Current xo state: %s', xo_data) 119 120 self.assertEqual( 121 intkey_state, 122 self.intkey_verifier.state_after_n_updates(num), 123 'Wrong intkey state') 124 125 self.assertEqual( 126 xo_data, 127 self.xo_verifier.state_after_n_updates(num), 128 'Wrong xo state') 129 130 131 # sending commands 132 133 def _send_xo_cmd(cmd_str): 134 LOGGER.info('Sending xo cmd') 135 subprocess.run( 136 shlex.split(cmd_str), 137 stdout=subprocess.PIPE, 138 stderr=subprocess.PIPE, 139 check=True) 140 141 142 def _send_intkey_cmd(txns): 143 batch = IntkeyMessageFactory().create_batch(txns) 144 LOGGER.info('Sending intkey txns') 145 _post_batch(batch) 146 147 # rest_api calls 148 149 150 def _post_batch(batch): 151 headers = {'Content-Type': 'application/octet-stream'} 152 response = _query_rest_api( 153 '/batches', data=batch, headers=headers, expected_code=202) 154 return _submit_request('{}&wait={}'.format(response['link'], WAIT)) 155 156 157 def _get_intkey_data(): 158 state = _get_intkey_state() 159 # state is a list of dictionaries: { data: ..., address: ... } 160 dicts = [cbor.loads(b64decode(entry['data'])) for entry in state] 161 LOGGER.debug(dicts) 162 data = {k: v for d in dicts for k, v in d.items()} # merge dicts 163 return data 164 165 166 def _get_xo_data(): 167 state = _get_xo_state() 168 data = b64decode(state[0]['data']).decode().split('|')[0].split(',') 169 game_name, board, turn, _, _ = data 170 return board, turn, game_name 171 172 173 def _get_intkey_state(): 174 state = _get_state_prefix(INTKEY_PREFIX) 175 return state 176 177 178 def _get_xo_state(): 179 state = _get_state_prefix(XO_PREFIX) 180 return state 181 182 183 def _get_state_prefix(prefix): 184 response = _query_rest_api('/state?address=' + prefix) 185 return response['data'] 186 187 188 def _query_rest_api(suffix='', data=None, headers=None, expected_code=200): 189 if headers is None: 190 headers = {} 191 url = 'http://rest-api:8008' + suffix 192 return _submit_request( 193 urllib.request.Request(url, data, headers), 194 expected_code=expected_code) 195 196 197 def _submit_request(request, expected_code=200): 198 conn = urllib.request.urlopen(request) 199 assert expected_code == conn.getcode() 200 201 response = conn.read().decode('utf-8') 202 return json.loads(response) 203 204 # verifiers 205 206 207 class XoTestVerifier: 208 def __init__(self): 209 self.xo_cmds = ( 210 'xo create game --wait {}'.format(WAIT), 211 'xo take game 5 --wait {}'.format(WAIT), 212 'xo take game 5 --wait {}'.format(WAIT), 213 'xo take game 9 --wait {}'.format(WAIT), 214 'xo create game --wait {}'.format(WAIT), 215 'xo take game 4 --wait {}'.format(WAIT), 216 ) 217 218 def state_after_n_updates(self, num): 219 state = { 220 0: ('---------', 'P1-NEXT', 'game'), 221 1: ('----X----', 'P2-NEXT', 'game'), 222 2: ('----X---O', 'P1-NEXT', 'game'), 223 3: ('---XX---O', 'P2-NEXT', 'game') 224 } 225 226 try: 227 return state[num] 228 except KeyError: 229 return () 230 231 232 class IntkeyTestVerifier: 233 def __init__(self): 234 self.valid = 'ragdoll', 'sphynx', 'van' 235 self.invalid = 'manx', 'persian', 'siamese' 236 self.verbs = 'inc', 'dec', 'inc' 237 self.sets = 'set', 'set', 'set' 238 self.incdec = 11, 13, 10 239 self.initial = 110, 143, 130 240 241 self.populate = tuple(zip(self.sets, self.valid, self.initial)) 242 self.valid_txns = tuple(zip(self.verbs, self.valid, self.incdec)) 243 self.invalid_txns = tuple(zip(self.verbs, self.invalid, self.incdec)) 244 245 self.intkey_cmds = ( 246 self.populate, 247 self.valid_txns, 248 self.invalid_txns, 249 self.valid_txns, 250 self.populate, 251 self.valid_txns, 252 ) 253 254 def state_after_n_updates(self, num): 255 ops = { 256 'inc': operator.add, 257 'dec': operator.sub 258 } 259 260 expected_values = [ 261 ops[verb](init, (val * num)) 262 for verb, init, val 263 in zip(self.verbs, self.initial, self.incdec) 264 ] 265 266 return {word: val for word, val in zip(self.valid, expected_values)}