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)}