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('\"')