github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/integration/sawtooth_integration/tests/test_shutdown_smoke.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=broad-except
    17  
    18  import unittest
    19  
    20  import logging
    21  import os
    22  import socket
    23  import subprocess
    24  import time
    25  import uuid
    26  
    27  LOGGER = logging.getLogger(__name__)
    28  
    29  
    30  class TestShutdownSmoke(unittest.TestCase):
    31      @classmethod
    32      def setUpClass(cls):
    33          cls._sawtooth_core = cls._find_host_sawtooth_core()
    34          cls._id = os.environ.get("ISOLATION_ID", "latest")
    35          cls._validator_image = "{}:{}".format(
    36              os.environ.get("VALIDATOR_IMAGE_NAME"),
    37              cls._id)
    38  
    39      @unittest.skip("Skipping until STL-120 is complete: has periodic failures")
    40      def test_resting_shutdown_sigint(self):
    41          """Tests that SIGINT will cause validators with and without
    42          genesis to gracefully exit.
    43  
    44          Notes:
    45              1) A genesis validator and a non-genesis validator are started with
    46              the non-genesis validator specifying the genesis validator as
    47              a peer.
    48              2) The SIGINT os signal is sent to both validators.
    49              3) The validators' return codes are checked and asserted to be 0.
    50              4) Repeat step 1.
    51              5) The SIGTERM os signal is sent to both validators.
    52              6) The validators' return codes are checked and asserted to be 0.
    53          """
    54  
    55          # 1)
    56          containers = self._startup()
    57  
    58          try:
    59              # 2)
    60              for c in containers:
    61                  self._send_docker_signal('SIGINT', c)
    62              initial_time = time.time()
    63              # 3)
    64              sigint_exit_statuses = self._wait_for_containers_exit_status(
    65                  containers)
    66  
    67              end_time = time.time() - initial_time
    68              LOGGER.warning("Containers exited with sigint in %s seconds",
    69                             end_time)
    70  
    71              self.assertEqual(len(sigint_exit_statuses), len(containers))
    72              for s in sigint_exit_statuses:
    73                  self.assertEqual(s, 0)
    74  
    75              self._log_and_clean_up(containers)
    76          except Exception as e:
    77              self._log_and_clean_up(containers)
    78              self.fail(str(e))
    79  
    80      @unittest.skip("Skipping until STL-120 is complete: has periodic failures")
    81      def test_resting_shutdown_sigterm(self):
    82          """Tests that SIGTERM will cause validators with and without
    83          genesis to gracefully exit.
    84  
    85          Notes:
    86              1) A genesis validator and a non-genesis validator are started with
    87              the non-genesis validator specifying the genesis validator as
    88              a peer.
    89              2) The SIGTERM os signal is sent to both validators.
    90              3) The validators' return codes are checked and asserted to be 0.
    91          """
    92  
    93          # 1)
    94          containers = self._startup()
    95  
    96          try:
    97              # 2)
    98              for c in containers:
    99                  self._send_docker_signal('SIGTERM', c)
   100              initial_time = time.time()
   101  
   102              # 3)
   103              sigterm_exit_statuses = self._wait_for_containers_exit_status(
   104                  containers)
   105              end_time = time.time() - initial_time
   106              LOGGER.warning("Containers exited with sigterm in %s seconds",
   107                             end_time)
   108              self.assertEqual(len(sigterm_exit_statuses), len(containers))
   109              for s in sigterm_exit_statuses:
   110                  self.assertEqual(s, 0)
   111  
   112              self._log_and_clean_up(containers)
   113          except Exception as e:
   114              self._log_and_clean_up(containers)
   115              self.fail(str(e))
   116  
   117      def _send_docker_signal(self, sig, container_name):
   118          """
   119          Args:
   120              sig (str): examples: SIGTERM, SIGINT
   121              container_name (str): The name of the docker container
   122          """
   123          args = ['docker', 'kill', '--signal={}'.format(sig), container_name]
   124  
   125          # Not catching the CalledProcessError so the test errors and stops
   126          # if there is a problem calling docker.
   127          subprocess.run(
   128              args, stdout=subprocess.PIPE,
   129              stderr=subprocess.PIPE, check=True)
   130  
   131      def _log_and_clean_up(self, containers):
   132          for container in containers:
   133              self._docker_logs(container)
   134          self._remove_docker_containers(containers)
   135  
   136      def _docker_logs(self, container):
   137          return subprocess.check_output(['docker', 'logs', container])
   138  
   139      def _wait_for_containers_exit_status(self, containers):
   140          """Wait for all of the specified containers to exit
   141          and return their exit codes.
   142          Args:
   143              containers (list of str): The containers to wait to exit.
   144  
   145          Returns:
   146              list of int: The list of return codes for the process in each
   147                  container.
   148  
   149          """
   150          wait = ['docker', 'wait'] + containers
   151          handle = subprocess.Popen(
   152              args=wait,
   153              stdout=subprocess.PIPE,
   154              universal_newlines=True)
   155          try:
   156              output, _ = handle.communicate(timeout=35)
   157              return [int(e) for e in output.strip().split('\n')]
   158          except subprocess.TimeoutExpired:
   159              handle.kill()
   160              LOGGER.warning("Docker timed out waiting for %s to exit",
   161                             containers)
   162              return []
   163  
   164      def _start_container(self, container):
   165          start = ['docker', 'start', container]
   166          subprocess.run(start, timeout=15, check=True)
   167  
   168      def _docker_run(self, args):
   169          return subprocess.check_output(['docker', 'run'] + args,
   170                                         universal_newlines=True).strip('\n')
   171  
   172      def _run_genesis(self):
   173          return self._docker_run(
   174              ['-d',
   175               '-v',
   176               '{}:/project/sawtooth-core'.format(self._sawtooth_core),
   177               '-v',
   178               '/etc/sawtooth',
   179               '-v',
   180               '/var/lib/sawtooth',
   181               self._validator_image,
   182               'bash',
   183               '-c',
   184               "sawadm keygen && sawadm genesis"])
   185  
   186      def _start_validator(self, prior_container, early, extra):
   187          return self._docker_run(
   188              ['-d',
   189               '--volumes-from',
   190               prior_container,
   191               *early,
   192               self._validator_image,
   193               'validator',
   194               '-vv',
   195               *extra])
   196  
   197      def _remove_docker_containers(self, containers):
   198          return subprocess.check_call(['docker', 'rm', '-f'] + containers)
   199  
   200      def _run_keygen_non_genesis(self):
   201          return self._docker_run(
   202              ['-d',
   203               '-v',
   204               '{}:/project/sawtooth-core'.format(self._sawtooth_core),
   205               '-v',
   206               '/etc/sawtooth',
   207               self._validator_image,
   208               "bash",
   209               '-c',
   210               "sawadm keygen"])
   211  
   212      def _startup(self):
   213          containers = []
   214          try:
   215              genesis = self._run_genesis()
   216              self._wait_for_containers_exit_status([genesis])
   217              genesis_name = str(uuid.uuid4())
   218              validator_genesis = self._start_validator(
   219                  genesis,
   220                  ['--name', genesis_name],
   221                  ['--endpoint', 'tcp://{}:8800'.format(genesis_name),
   222                   '--bind', 'component:tcp://eth0:4004',
   223                   '--bind', 'network:tcp://eth0:8800'])
   224              containers.append(validator_genesis)
   225              self._remove_docker_containers([genesis])
   226              keygen = self._run_keygen_non_genesis()
   227              self._wait_for_containers_exit_status([keygen])
   228              validator_1_name = str(uuid.uuid4())
   229              validator_non_genesis = self._start_validator(
   230                  keygen, ['--link', validator_genesis,
   231                           '--name', validator_1_name],
   232                  ['--peers', 'tcp://{}:8800'.format(genesis_name),
   233                   '--endpoint', 'tcp://{}:8800'.format(validator_1_name),
   234                   '--bind', 'component:tcp://eth0:4004',
   235                   '--bind', 'network:tcp://eth0:8800'])
   236              containers.append(validator_non_genesis)
   237              self._remove_docker_containers([keygen])
   238              # Make sure that the validators have completed startup -- cli path
   239              # and key loading, genesis check and creation
   240              time.sleep(3)
   241              return containers
   242          except Exception as e:
   243              self._remove_docker_containers(containers)
   244              self.fail(str(e))
   245  
   246      @classmethod
   247      def _find_host_sawtooth_core(cls):
   248          hostname = socket.gethostname()
   249          return subprocess.check_output(
   250              ['docker', 'inspect',
   251               '--format=\"{{ range .Mounts }}'
   252               '{{ if and (eq .Destination "/project/sawtooth-core") '
   253               '(eq .Type "bind") }}{{ .Source }}{{ end }}{{ end }}\"',
   254               hostname],
   255              universal_newlines=True).strip('\n').strip('\"')