environment.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import errno
  2. import os
  3. import socket
  4. import subprocess
  5. import time
  6. from contextlib import closing
  7. import signal
  8. def before_scenario(context, scenario):
  9. context.debug = 'DEBUG' in os.environ and os.environ['DEBUG'] == 'ON'
  10. if context.debug:
  11. print("DEBUG=ON\n")
  12. print(f"\x1b[33;42mStarting new scenario: {scenario.name}!\x1b[0m\n")
  13. port = 8080
  14. if 'PORT' in os.environ:
  15. port = int(os.environ['PORT'])
  16. if is_server_listening("localhost", port):
  17. assert False, "Server already started"
  18. def after_scenario(context, scenario):
  19. if context.server_process is None:
  20. return
  21. if scenario.status == "failed":
  22. if 'GITHUB_ACTIONS' in os.environ:
  23. print(f"\x1b[33;101mSCENARIO FAILED: {scenario.name} server logs:\x1b[0m\n\n")
  24. if os.path.isfile('llama.log'):
  25. with closing(open('llama.log', 'r')) as f:
  26. for line in f:
  27. print(line)
  28. if not is_server_listening(context.server_fqdn, context.server_port):
  29. print("\x1b[33;101mERROR: Server stopped listening\x1b[0m\n")
  30. if not pid_exists(context.server_process.pid):
  31. assert False, f"Server not running pid={context.server_process.pid} ..."
  32. server_graceful_shutdown(context)
  33. # Wait few for socket to free up
  34. time.sleep(0.05)
  35. attempts = 0
  36. while pid_exists(context.server_process.pid) or is_server_listening(context.server_fqdn, context.server_port):
  37. server_kill(context)
  38. time.sleep(0.1)
  39. attempts += 1
  40. if attempts > 5:
  41. server_kill_hard(context)
  42. def server_graceful_shutdown(context):
  43. print(f"shutting down server pid={context.server_process.pid} ...\n")
  44. if os.name == 'nt':
  45. os.kill(context.server_process.pid, signal.CTRL_C_EVENT)
  46. else:
  47. os.kill(context.server_process.pid, signal.SIGINT)
  48. def server_kill(context):
  49. print(f"killing server pid={context.server_process.pid} ...\n")
  50. context.server_process.kill()
  51. def server_kill_hard(context):
  52. pid = context.server_process.pid
  53. path = context.server_path
  54. print(f"Server dangling exits, hard killing force {pid}={path}...\n")
  55. if os.name == 'nt':
  56. process = subprocess.check_output(['taskkill', '/F', '/pid', str(pid)]).decode()
  57. print(process)
  58. else:
  59. os.kill(-pid, signal.SIGKILL)
  60. def is_server_listening(server_fqdn, server_port):
  61. with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
  62. result = sock.connect_ex((server_fqdn, server_port))
  63. _is_server_listening = result == 0
  64. if _is_server_listening:
  65. print(f"server is listening on {server_fqdn}:{server_port}...\n")
  66. return _is_server_listening
  67. def pid_exists(pid):
  68. """Check whether pid exists in the current process table."""
  69. if pid < 0:
  70. return False
  71. if os.name == 'nt':
  72. output = subprocess.check_output(['TASKLIST', '/FI', f'pid eq {pid}']).decode()
  73. print(output)
  74. return "No tasks are running" not in output
  75. else:
  76. try:
  77. os.kill(pid, 0)
  78. except OSError as e:
  79. return e.errno == errno.EPERM
  80. else:
  81. return True