/appengine_django/tests/commands_test.py

http://google-app-engine-django.googlecode.com/ · Python · 186 lines · 107 code · 15 blank · 64 comment · 10 complexity · e40e8287f7a61e04d9d18e5a6a9c747f MD5 · raw file

  1. #!/usr/bin/python2.4
  2. #
  3. # Copyright 2008 Google Inc.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. """
  17. Tests that the manage.py commands execute correctly.
  18. These tests only verify that the commands execute and exit with a success code.
  19. They are intended to catch import exceptions and similar problems, it is left
  20. up to tests in other modules to verify that the functionality of each command
  21. works correctly.
  22. """
  23. import os
  24. import re
  25. import signal
  26. import subprocess
  27. import tempfile
  28. import time
  29. import unittest
  30. import sys
  31. from django.db.models import get_models
  32. from google.appengine.ext import db
  33. from appengine_django.models import BaseModel
  34. from appengine_django.models import ModelManager
  35. from appengine_django.models import ModelOptions
  36. from appengine_django.models import RegistrationTestModel
  37. class CommandsTest(unittest.TestCase):
  38. """Unit tests for the manage.py commands."""
  39. # How many seconds to wait for a command to exit.
  40. COMMAND_TIMEOUT = 10
  41. def runCommand(self, command, args=None, int_after=None, input=None):
  42. """Helper to run the specified command in a child process.
  43. Args:
  44. command: The name of the command to run.
  45. args: List of command arguments to run the command with.
  46. int_after: If set to a positive integer, SIGINT will be sent to the
  47. running child process after this many seconds to cause an exit. This
  48. should be less than the COMMAND_TIMEOUT value (10 seconds).
  49. input: A string to write to stdin when the command starts. stdin is
  50. closed after the string is written.
  51. Returns:
  52. rc: The integer return code of the process.
  53. output: A string containing the childs output.
  54. """
  55. if not args:
  56. args = []
  57. start = time.time()
  58. int_sent = False
  59. fd = subprocess.PIPE
  60. child = subprocess.Popen([sys.executable, "manage.py", command] + args,
  61. stdin=fd, stdout=fd, stderr=fd, cwd=os.getcwdu())
  62. if input:
  63. child.stdin.write(input)
  64. child.stdin.close()
  65. while 1:
  66. rc = child.poll()
  67. if rc is not None:
  68. # Child has exited.
  69. break
  70. elapsed = time.time() - start
  71. if int_after and int_after > 0 and elapsed > int_after and not int_sent:
  72. # Sent SIGINT as requested, give child time to exit cleanly.
  73. os.kill(child.pid, signal.SIGINT)
  74. start = time.time()
  75. int_sent = True
  76. continue
  77. if elapsed < self.COMMAND_TIMEOUT:
  78. continue
  79. # Command is over time, kill and exit loop.
  80. os.kill(child.pid, signal.SIGKILL)
  81. time.sleep(2) # Give time for the signal to be received.
  82. break
  83. # Return status and output.
  84. return rc, child.stdout.read(), child.stderr.read()
  85. def assertCommandSucceeds(self, command, *args, **kwargs):
  86. """Asserts that the specified command successfully completes.
  87. Args:
  88. command: The name of the command to run.
  89. All other arguments are passed directly through to the runCommand
  90. routine.
  91. Raises:
  92. This function does not return anything but will raise assertion errors if
  93. the command does not exit successfully.
  94. """
  95. rc, stdout, stderr = self.runCommand(command, *args, **kwargs)
  96. fd, tempname = tempfile.mkstemp()
  97. os.write(fd, stdout)
  98. os.close(fd)
  99. self.assertEquals(0, rc,
  100. "%s did not return successfully (rc: %d): Output in %s" %
  101. (command, rc, tempname))
  102. os.unlink(tempname)
  103. def getCommands(self):
  104. """Returns a list of valid commands for manage.py.
  105. Args:
  106. None
  107. Returns:
  108. A list of valid commands for manage.py as read from manage.py's help
  109. output.
  110. """
  111. rc, stdout, stderr = self.runCommand("help")
  112. parts = re.split("Available subcommands:", stderr)
  113. if len(parts) < 2:
  114. return []
  115. return [t.strip() for t in parts[-1].split("\n") if t.strip()]
  116. def testDiffSettings(self):
  117. """Tests the diffsettings command."""
  118. self.assertCommandSucceeds("diffsettings")
  119. def testDumpData(self):
  120. """Tests the dumpdata command."""
  121. self.assertCommandSucceeds("dumpdata")
  122. def testFlush(self):
  123. """Tests the flush command."""
  124. self.assertCommandSucceeds("flush")
  125. def testLoadData(self):
  126. """Tests the loaddata command."""
  127. self.assertCommandSucceeds("loaddata")
  128. def testLoadData(self):
  129. """Tests the loaddata command."""
  130. self.assertCommandSucceeds("loaddata")
  131. def testReset(self):
  132. """Tests the reste command."""
  133. self.assertCommandSucceeds("reset", ["appengine_django"])
  134. # Disabled due to flakiness - re-enable when it can be guaranteed to succeed
  135. # reliably.
  136. #def testRunserver(self):
  137. # """Tests the runserver command."""
  138. # self.assertCommandSucceeds("runserver", int_after=2.0)
  139. def testShell(self):
  140. """Tests the shell command."""
  141. self.assertCommandSucceeds("shell", input="exit")
  142. def testUpdate(self):
  143. """Tests that the update command exists.
  144. Cannot test that it works without mocking out parts of dev_appserver so for
  145. now we just assume that if it is present it will work.
  146. """
  147. cmd_list = self.getCommands()
  148. self.assert_("update" in cmd_list)
  149. def testZipCommandListFiltersCorrectly(self):
  150. """When running under a zipfile test that only valid commands are found."""
  151. cmd_list = self.getCommands()
  152. self.assert_("__init__" not in cmd_list)
  153. self.assert_("base" not in cmd_list)