autoreload_test.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import os
  2. import shutil
  3. import subprocess
  4. from subprocess import Popen
  5. import sys
  6. from tempfile import mkdtemp
  7. import time
  8. import unittest
  9. class AutoreloadTest(unittest.TestCase):
  10. def setUp(self):
  11. self.path = mkdtemp()
  12. def tearDown(self):
  13. try:
  14. shutil.rmtree(self.path)
  15. except OSError:
  16. # Windows disallows deleting files that are in use by
  17. # another process, and even though we've waited for our
  18. # child process below, it appears that its lock on these
  19. # files is not guaranteed to be released by this point.
  20. # Sleep and try again (once).
  21. time.sleep(1)
  22. shutil.rmtree(self.path)
  23. def test_reload_module(self):
  24. main = """\
  25. import os
  26. import sys
  27. from tornado import autoreload
  28. # This import will fail if path is not set up correctly
  29. import testapp
  30. print('Starting')
  31. if 'TESTAPP_STARTED' not in os.environ:
  32. os.environ['TESTAPP_STARTED'] = '1'
  33. sys.stdout.flush()
  34. autoreload._reload()
  35. """
  36. # Create temporary test application
  37. os.mkdir(os.path.join(self.path, "testapp"))
  38. open(os.path.join(self.path, "testapp/__init__.py"), "w").close()
  39. with open(os.path.join(self.path, "testapp/__main__.py"), "w") as f:
  40. f.write(main)
  41. # Make sure the tornado module under test is available to the test
  42. # application
  43. pythonpath = os.getcwd()
  44. if "PYTHONPATH" in os.environ:
  45. pythonpath += os.pathsep + os.environ["PYTHONPATH"]
  46. p = Popen(
  47. [sys.executable, "-m", "testapp"],
  48. stdout=subprocess.PIPE,
  49. cwd=self.path,
  50. env=dict(os.environ, PYTHONPATH=pythonpath),
  51. universal_newlines=True,
  52. )
  53. out = p.communicate()[0]
  54. self.assertEqual(out, "Starting\nStarting\n")
  55. def test_reload_wrapper_preservation(self):
  56. # This test verifies that when `python -m tornado.autoreload`
  57. # is used on an application that also has an internal
  58. # autoreload, the reload wrapper is preserved on restart.
  59. main = """\
  60. import os
  61. import sys
  62. # This import will fail if path is not set up correctly
  63. import testapp
  64. if 'tornado.autoreload' not in sys.modules:
  65. raise Exception('started without autoreload wrapper')
  66. import tornado.autoreload
  67. print('Starting')
  68. sys.stdout.flush()
  69. if 'TESTAPP_STARTED' not in os.environ:
  70. os.environ['TESTAPP_STARTED'] = '1'
  71. # Simulate an internal autoreload (one not caused
  72. # by the wrapper).
  73. tornado.autoreload._reload()
  74. else:
  75. # Exit directly so autoreload doesn't catch it.
  76. os._exit(0)
  77. """
  78. # Create temporary test application
  79. os.mkdir(os.path.join(self.path, "testapp"))
  80. init_file = os.path.join(self.path, "testapp", "__init__.py")
  81. open(init_file, "w").close()
  82. main_file = os.path.join(self.path, "testapp", "__main__.py")
  83. with open(main_file, "w") as f:
  84. f.write(main)
  85. # Make sure the tornado module under test is available to the test
  86. # application
  87. pythonpath = os.getcwd()
  88. if "PYTHONPATH" in os.environ:
  89. pythonpath += os.pathsep + os.environ["PYTHONPATH"]
  90. autoreload_proc = Popen(
  91. [sys.executable, "-m", "tornado.autoreload", "-m", "testapp"],
  92. stdout=subprocess.PIPE,
  93. cwd=self.path,
  94. env=dict(os.environ, PYTHONPATH=pythonpath),
  95. universal_newlines=True,
  96. )
  97. # This timeout needs to be fairly generous for pypy due to jit
  98. # warmup costs.
  99. for i in range(40):
  100. if autoreload_proc.poll() is not None:
  101. break
  102. time.sleep(0.1)
  103. else:
  104. autoreload_proc.kill()
  105. raise Exception("subprocess failed to terminate")
  106. out = autoreload_proc.communicate()[0]
  107. self.assertEqual(out, "Starting\n" * 2)