gcloud 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data.tar.gz.sig +2 -3
  2. data/CHANGELOG +4 -0
  3. data/LICENSE +674 -0
  4. data/Manifest +111 -0
  5. data/README.md +4 -3
  6. data/bin/gcutil +53 -0
  7. data/gcloud.gemspec +4 -3
  8. data/packages/gcutil-1.7.1/CHANGELOG +197 -0
  9. data/packages/gcutil-1.7.1/LICENSE +202 -0
  10. data/packages/gcutil-1.7.1/VERSION +1 -0
  11. data/packages/gcutil-1.7.1/gcutil +53 -0
  12. data/packages/gcutil-1.7.1/lib/google_api_python_client/LICENSE +23 -0
  13. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/__init__.py +1 -0
  14. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/discovery.py +743 -0
  15. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/errors.py +123 -0
  16. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/ext/__init__.py +0 -0
  17. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/http.py +1443 -0
  18. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/mimeparse.py +172 -0
  19. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/model.py +385 -0
  20. data/packages/gcutil-1.7.1/lib/google_api_python_client/apiclient/schema.py +303 -0
  21. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/__init__.py +1 -0
  22. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/anyjson.py +32 -0
  23. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/appengine.py +528 -0
  24. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/client.py +1139 -0
  25. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/clientsecrets.py +105 -0
  26. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/crypt.py +244 -0
  27. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/django_orm.py +124 -0
  28. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/file.py +107 -0
  29. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/locked_file.py +343 -0
  30. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/multistore_file.py +379 -0
  31. data/packages/gcutil-1.7.1/lib/google_api_python_client/oauth2client/tools.py +174 -0
  32. data/packages/gcutil-1.7.1/lib/google_api_python_client/uritemplate/__init__.py +147 -0
  33. data/packages/gcutil-1.7.1/lib/google_apputils/LICENSE +202 -0
  34. data/packages/gcutil-1.7.1/lib/google_apputils/google/__init__.py +3 -0
  35. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/__init__.py +3 -0
  36. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/app.py +356 -0
  37. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/appcommands.py +783 -0
  38. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/basetest.py +1260 -0
  39. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/datelib.py +421 -0
  40. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/debug.py +60 -0
  41. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/file_util.py +181 -0
  42. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/resources.py +67 -0
  43. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/run_script_module.py +217 -0
  44. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/setup_command.py +159 -0
  45. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/shellutil.py +49 -0
  46. data/packages/gcutil-1.7.1/lib/google_apputils/google/apputils/stopwatch.py +204 -0
  47. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/__init__.py +0 -0
  48. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper.py +140 -0
  49. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auth_helper_test.py +149 -0
  50. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth.py +130 -0
  51. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/auto_auth_test.py +75 -0
  52. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds.py +128 -0
  53. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/basic_cmds_test.py +111 -0
  54. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base.py +1808 -0
  55. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/command_base_test.py +1651 -0
  56. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta13.json +2851 -0
  57. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/compute/v1beta14.json +3361 -0
  58. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds.py +342 -0
  59. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/disk_cmds_test.py +474 -0
  60. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds.py +344 -0
  61. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/firewall_cmds_test.py +231 -0
  62. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/flags_cache.py +274 -0
  63. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil +89 -0
  64. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/gcutil_logging.py +69 -0
  65. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds.py +262 -0
  66. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/image_cmds_test.py +172 -0
  67. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds.py +1506 -0
  68. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/instance_cmds_test.py +1904 -0
  69. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds.py +91 -0
  70. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/kernel_cmds_test.py +56 -0
  71. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds.py +106 -0
  72. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/machine_type_cmds_test.py +59 -0
  73. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata.py +96 -0
  74. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_lib.py +357 -0
  75. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/metadata_test.py +84 -0
  76. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_api.py +420 -0
  77. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/mock_metadata.py +58 -0
  78. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds.py +824 -0
  79. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/move_cmds_test.py +307 -0
  80. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds.py +178 -0
  81. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/network_cmds_test.py +133 -0
  82. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds.py +181 -0
  83. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/operation_cmds_test.py +196 -0
  84. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/path_initializer.py +38 -0
  85. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds.py +173 -0
  86. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/project_cmds_test.py +111 -0
  87. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes.py +61 -0
  88. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/scopes_test.py +50 -0
  89. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds.py +276 -0
  90. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/snapshot_cmds_test.py +260 -0
  91. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys.py +266 -0
  92. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/ssh_keys_test.py +128 -0
  93. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/table_formatter.py +563 -0
  94. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool.py +188 -0
  95. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/thread_pool_test.py +88 -0
  96. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils.py +208 -0
  97. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/utils_test.py +193 -0
  98. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version.py +17 -0
  99. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker.py +246 -0
  100. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/version_checker_test.py +271 -0
  101. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds.py +151 -0
  102. data/packages/gcutil-1.7.1/lib/google_compute_engine/gcutil/zone_cmds_test.py +60 -0
  103. data/packages/gcutil-1.7.1/lib/httplib2/LICENSE +21 -0
  104. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/__init__.py +1630 -0
  105. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/cacerts.txt +714 -0
  106. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/iri2uri.py +110 -0
  107. data/packages/gcutil-1.7.1/lib/httplib2/httplib2/socks.py +438 -0
  108. data/packages/gcutil-1.7.1/lib/iso8601/LICENSE +20 -0
  109. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/__init__.py +1 -0
  110. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/iso8601.py +102 -0
  111. data/packages/gcutil-1.7.1/lib/iso8601/iso8601/test_iso8601.py +111 -0
  112. data/packages/gcutil-1.7.1/lib/python_gflags/AUTHORS +2 -0
  113. data/packages/gcutil-1.7.1/lib/python_gflags/LICENSE +28 -0
  114. data/packages/gcutil-1.7.1/lib/python_gflags/gflags.py +2862 -0
  115. data/packages/gcutil-1.7.1/lib/python_gflags/gflags2man.py +544 -0
  116. data/packages/gcutil-1.7.1/lib/python_gflags/gflags_validators.py +187 -0
  117. metadata +118 -5
  118. metadata.gz.sig +0 -0
@@ -0,0 +1,1260 @@
1
+ #!/usr/bin/env python
2
+ # Copyright 2010 Google Inc. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS-IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ """Base functionality for google tests.
17
+
18
+ This module contains base classes and high-level functions for Google-style
19
+ tests.
20
+ """
21
+
22
+ __author__ = 'dborowitz@google.com (Dave Borowitz)'
23
+
24
+ import commands
25
+ import difflib
26
+ import getpass
27
+ import itertools
28
+ import os
29
+ import re
30
+ import subprocess
31
+ import sys
32
+ import tempfile
33
+ import types
34
+
35
+
36
+ # unittest2 is a backport of Python 2.7's unittest for Python 2.6, so
37
+ # we don't need it if we are running 2.7 or newer.
38
+
39
+ if sys.version_info < (2, 7):
40
+ import unittest2 as unittest
41
+ else:
42
+ import unittest
43
+
44
+ from google.apputils import app
45
+ import gflags as flags
46
+ from google.apputils import shellutil
47
+
48
+ FLAGS = flags.FLAGS
49
+
50
+ # ----------------------------------------------------------------------
51
+ # Internal functions to extract default flag values from environment.
52
+ # ----------------------------------------------------------------------
53
+ def _GetDefaultTestRandomSeed():
54
+ random_seed = 301
55
+ value = os.environ.get('TEST_RANDOM_SEED', '')
56
+ try:
57
+ random_seed = int(value)
58
+ except ValueError:
59
+ pass
60
+ return random_seed
61
+
62
+
63
+ def _GetDefaultTestTmpdir():
64
+ tmpdir = os.environ.get('TEST_TMPDIR', '')
65
+ if not tmpdir:
66
+ tmpdir = os.path.join(tempfile.gettempdir(), 'google_apputils_basetest')
67
+
68
+ return tmpdir
69
+
70
+
71
+ flags.DEFINE_integer('test_random_seed', _GetDefaultTestRandomSeed(),
72
+ 'Random seed for testing. Some test frameworks may '
73
+ 'change the default value of this flag between runs, so '
74
+ 'it is not appropriate for seeding probabilistic tests.',
75
+ allow_override=1)
76
+ flags.DEFINE_string('test_srcdir',
77
+ os.environ.get('TEST_SRCDIR', ''),
78
+ 'Root of directory tree where source files live',
79
+ allow_override=1)
80
+ flags.DEFINE_string('test_tmpdir', _GetDefaultTestTmpdir(),
81
+ 'Directory for temporary testing files',
82
+ allow_override=1)
83
+
84
+
85
+ class BeforeAfterTestCaseMeta(type):
86
+
87
+ """Adds setUpTestCase() and tearDownTestCase() methods.
88
+
89
+ These may be needed for setup and teardown of shared fixtures usually because
90
+ such fixtures are expensive to setup and teardown (eg Perforce clients). When
91
+ using such fixtures, care should be taken to keep each test as independent as
92
+ possible (eg via the use of sandboxes).
93
+
94
+ Example:
95
+
96
+ class MyTestCase(basetest.TestCase):
97
+
98
+ __metaclass__ = basetest.BeforeAfterTestCaseMeta
99
+
100
+ @classmethod
101
+ def setUpTestCase(cls):
102
+ cls._resource = foo.ReallyExpensiveResource()
103
+
104
+ @classmethod
105
+ def tearDownTestCase(cls):
106
+ cls._resource.Destroy()
107
+
108
+ def testSomething(self):
109
+ self._resource.Something()
110
+ ...
111
+ """
112
+
113
+ _test_loader = unittest.defaultTestLoader
114
+
115
+ def __init__(cls, name, bases, dict):
116
+ super(BeforeAfterTestCaseMeta, cls).__init__(name, bases, dict)
117
+
118
+ # Notes from mtklein
119
+
120
+ # This code can be tricky to think about. Here are a few things to remember
121
+ # as you read through it.
122
+
123
+ # When inheritance is involved, this __init__ is called once on each class
124
+ # in the inheritance chain when that class is defined. In a typical
125
+ # scenario where a BaseClass inheriting from TestCase declares the
126
+ # __metaclass__ and SubClass inherits from BaseClass, __init__ will be first
127
+ # called with cls=BaseClass when BaseClass is defined, and then called later
128
+ # with cls=SubClass when SubClass is defined.
129
+
130
+ # To know when to call setUpTestCase and tearDownTestCase, this class wraps
131
+ # the setUp, tearDown, and test* methods in a TestClass. We'd like to only
132
+ # wrap those methods in the leaves of the inheritance tree, but we can't
133
+ # know when we're a leaf at wrapping time. So instead we wrap all the
134
+ # setUp, tearDown, and test* methods, but code them so that we only do the
135
+ # counting we want at the leaves, which we *can* detect when we've got an
136
+ # actual instance to look at --- i.e. self, when a method is running.
137
+
138
+ # Because we're wrapping at every level of inheritance, some methods get
139
+ # wrapped multiple times down the inheritance chain; if SubClass were to
140
+ # inherit, say, setUp or testFoo from BaseClass, that method would be
141
+ # wrapped twice, first by BaseClass then by SubClass. That's OK, because we
142
+ # ensure that the extra code we inject with these wrappers is idempotent.
143
+
144
+ # test_names are the test methods this class can see.
145
+ test_names = set(cls._test_loader.getTestCaseNames(cls))
146
+
147
+ # Each class keeps a set of the tests it still has to run. When it's empty,
148
+ # we know we should call tearDownTestCase. For now, it holds the sentinel
149
+ # value of None, acting as a indication that we need to call setUpTestCase,
150
+ # which fills in the actual tests to run.
151
+ cls.__tests_to_run = None
152
+
153
+ # These calls go through and monkeypatch various methods, in no particular
154
+ # order.
155
+ BeforeAfterTestCaseMeta.SetSetUpAttr(cls, test_names)
156
+ BeforeAfterTestCaseMeta.SetTearDownAttr(cls)
157
+ BeforeAfterTestCaseMeta.SetTestMethodAttrs(cls, test_names)
158
+ BeforeAfterTestCaseMeta.SetBeforeAfterTestCaseAttr()
159
+
160
+ # Just a little utility function to help with monkey-patching.
161
+ @staticmethod
162
+ def SetMethod(cls, method_name, replacement):
163
+ """Like setattr, but also preserves name, doc, and module metadata."""
164
+ original = getattr(cls, method_name)
165
+ replacement.__name__ = original.__name__
166
+ replacement.__doc__ = original.__doc__
167
+ replacement.__module__ = original.__module__
168
+ setattr(cls, method_name, replacement)
169
+
170
+ @staticmethod
171
+ def SetSetUpAttr(cls, test_names):
172
+ """Wraps setUp() with per-class setUp() functionality."""
173
+ # Remember that SetSetUpAttr is eventually called on each class in the
174
+ # inheritance chain. This line can be subtle because of inheritance. Say
175
+ # we've got BaseClass that defines setUp, and SubClass inheriting from it
176
+ # that doesn't define setUp. This method will run twice, and both times
177
+ # cls_setUp will be BaseClass.setUp. This is one of the tricky cases where
178
+ # setUp will be wrapped multiple times.
179
+ cls_setUp = cls.setUp
180
+
181
+ # We create a new setUp method that first checks to see if we need to run
182
+ # setUpTestCase (looking for the __tests_to_run==None flag), and then runs
183
+ # the original setUp method.
184
+ def setUp(self):
185
+ """Function that will encapsulate and replace cls.setUp()."""
186
+ # This line is unassuming but crucial to making this whole system work.
187
+ # It sets leaf to the class of the instance we're currently testing. That
188
+ # is, leaf is going to be a leaf class. It's not necessarily the same
189
+ # class as the parameter cls that's being passed in. For example, in the
190
+ # case above where setUp is in BaseClass, when we instantiate a SubClass
191
+ # and call setUp, we need leaf to be pointing at the class SubClass.
192
+ leaf = self.__class__
193
+
194
+ # The reason we want to do this is that it makes sure setUpTestCase is
195
+ # only run once, not once for each class down the inheritance chain. When
196
+ # multiply-wrapped, this extra code is called multiple times. In the
197
+ # running example:
198
+ #
199
+ # 1) cls=BaseClass: replace BaseClass' setUp with a wrapped setUp
200
+ # 2) cls=SubClass: set SubClass.setUp to what it thinks was its original
201
+ # setUp --- the wrapped setUp from 1)
202
+ #
203
+ # So it's double-wrapped, but that's OK. When we actually call setUp from
204
+ # an instance, we're calling the double-wrapped method. It sees
205
+ # __tests_to_run is None and fills that in. Then it calls what it thinks
206
+ # was its original setUp, the singly-wrapped setUp from BaseClass. The
207
+ # singly-wrapped setUp *skips* the if-statement, as it sees
208
+ # leaf.__tests_to_run is not None now. It just runs the real, original
209
+ # setUp().
210
+
211
+ # test_names is passed in from __init__, and holds all the test cases that
212
+ # cls can see. In the BaseClass call, that's probably the empty set, and
213
+ # for SubClass it'd have your test methods.
214
+
215
+ if leaf.__tests_to_run is None:
216
+ leaf.__tests_to_run = set(test_names)
217
+ self.setUpTestCase()
218
+ cls_setUp(self)
219
+
220
+ # Monkeypatch our new setUp method into the place of the original.
221
+ BeforeAfterTestCaseMeta.SetMethod(cls, 'setUp', setUp)
222
+
223
+ @staticmethod
224
+ def SetTearDownAttr(cls):
225
+ """Wraps tearDown() with per-class tearDown() functionality."""
226
+
227
+ # This is analagous to SetSetUpAttr, except of course it's patching tearDown
228
+ # to run tearDownTestCase when there are no more tests to run. All the same
229
+ # hairy logic applies.
230
+ cls_tearDown = cls.tearDown
231
+
232
+ def tearDown(self):
233
+ """Function that will encapsulate and replace cls.tearDown()."""
234
+ cls_tearDown(self)
235
+
236
+ leaf = self.__class__
237
+ # We need to make sure that tearDownTestCase is only run when
238
+ # we're executing this in the leaf class, so we need the
239
+ # explicit leaf == cls check below.
240
+ if (leaf.__tests_to_run is not None
241
+ and not leaf.__tests_to_run
242
+ and leaf == cls):
243
+ leaf.__tests_to_run = None
244
+ self.tearDownTestCase()
245
+
246
+ BeforeAfterTestCaseMeta.SetMethod(cls, 'tearDown', tearDown)
247
+
248
+ @staticmethod
249
+ def SetTestMethodAttrs(cls, test_names):
250
+ """Makes each test method first remove itself from the remaining set."""
251
+ # This makes each test case remove itself from the set of remaining tests.
252
+ # You might think that this belongs more logically in tearDown, and I'd
253
+ # agree except that tearDown doesn't know what test case it's tearing down!
254
+ # Instead we have the test method itself remove itself before attempting the
255
+ # test.
256
+
257
+ # Note that having the test remove itself after running doesn't work, as we
258
+ # never get to 'after running' for tests that fail.
259
+
260
+ # Like setUp and tearDown, the test case could conceivably be wrapped
261
+ # twice... but as noted it's an implausible situation to have an actual test
262
+ # defined in a base class. Just in case, we take the same precaution by
263
+ # looking in only the leaf class' set of __tests_to_run, and using discard()
264
+ # instead of remove() to make the operation idempotent.
265
+
266
+ for test_name in test_names:
267
+ cls_test = getattr(cls, test_name)
268
+
269
+ # The default parameters here make sure that each new test() function
270
+ # remembers its own values of cls_test and test_name. Without these
271
+ # default parameters, they'd all point to the values from the last
272
+ # iteration of the loop, causing some arbitrary test method to run
273
+ # multiple times and the others never. :(
274
+ def test(self, cls_test=cls_test, test_name=test_name):
275
+ leaf = self.__class__
276
+ leaf.__tests_to_run.discard(test_name)
277
+ return cls_test(self)
278
+
279
+ BeforeAfterTestCaseMeta.SetMethod(cls, test_name, test)
280
+
281
+ @staticmethod
282
+ def SetBeforeAfterTestCaseAttr():
283
+ # This just makes sure every TestCase has a setUpTestCase or
284
+ # tearDownTestCase, so that you can safely define only one or neither of
285
+ # them if you want.
286
+ TestCase.setUpTestCase = lambda self: None
287
+ TestCase.tearDownTestCase = lambda self: None
288
+
289
+
290
+ class TestCase(unittest.TestCase):
291
+ """Extension of unittest.TestCase providing more powerful assertions."""
292
+
293
+ maxDiff = 80 * 20
294
+
295
+ def __init__(self, methodName='runTest'):
296
+ super(TestCase, self).__init__(methodName)
297
+ self.__recorded_properties = {}
298
+
299
+ def shortDescription(self):
300
+ """Format both the test method name and the first line of its docstring.
301
+
302
+ If no docstring is given, only returns the method name.
303
+
304
+ This method overrides unittest.TestCase.shortDescription(), which
305
+ only returns the first line of the docstring, obscuring the name
306
+ of the test upon failure.
307
+
308
+ Returns:
309
+ desc: A short description of a test method.
310
+ """
311
+ desc = str(self)
312
+ # NOTE: super() is used here instead of directly invoking
313
+ # unittest.TestCase.shortDescription(self), because of the
314
+ # following line that occurs later on:
315
+ # unittest.TestCase = TestCase
316
+ # Because of this, direct invocation of what we think is the
317
+ # superclass will actually cause infinite recursion.
318
+ doc_first_line = super(TestCase, self).shortDescription()
319
+ if doc_first_line is not None:
320
+ desc = '\n'.join((desc, doc_first_line))
321
+ return desc
322
+
323
+ def assertSequenceStartsWith(self, prefix, whole, msg=None):
324
+ """An equality assertion for the beginning of ordered sequences.
325
+
326
+ If prefix is an empty sequence, it will raise an error unless whole is also
327
+ an empty sequence.
328
+
329
+ If prefix is not a sequence, it will raise an error if the first element of
330
+ whole does not match.
331
+
332
+ Args:
333
+ prefix: A sequence expected at the beginning of the whole parameter.
334
+ whole: The sequence in which to look for prefix.
335
+ msg: Optional message to append on failure.
336
+ """
337
+ try:
338
+ prefix_len = len(prefix)
339
+ except (TypeError, NotImplementedError):
340
+ prefix = [prefix]
341
+ prefix_len = 1
342
+
343
+ try:
344
+ whole_len = len(whole)
345
+ except (TypeError, NotImplementedError):
346
+ self.fail('For whole: len(%s) is not supported, it appears to be type: '
347
+ '%s' % (whole, type(whole)))
348
+
349
+ assert prefix_len <= whole_len, (
350
+ 'Prefix length (%d) is longer than whole length (%d).' %
351
+ (prefix_len, whole_len))
352
+
353
+ if not prefix_len and whole_len:
354
+ self.fail('Prefix length is 0 but whole length is %d: %s' %
355
+ (len(whole), whole))
356
+
357
+ try:
358
+ self.assertSequenceEqual(prefix, whole[:prefix_len], msg)
359
+ except AssertionError:
360
+ self.fail(msg or 'prefix: %s not found at start of whole: %s.' %
361
+ (prefix, whole))
362
+
363
+ def assertContainsSubset(self, expected_subset, actual_set, msg=None):
364
+ """Checks whether actual iterable is a superset of expected iterable."""
365
+ missing = set(expected_subset) - set(actual_set)
366
+ if not missing:
367
+ return
368
+
369
+ missing_msg = 'Missing elements %s\nExpected: %s\nActual: %s' % (
370
+ missing, expected_subset, actual_set)
371
+ if msg:
372
+ msg += ': %s' % missing_msg
373
+ else:
374
+ msg = missing_msg
375
+ self.fail(msg)
376
+
377
+ def assertSameElements(self, expected_seq, actual_seq, msg=None):
378
+ """Assert that two sequences have the same elements (in any order).
379
+
380
+ This method, unlike assertItemsEqual, doesn't care about any
381
+ duplicates in the expected and actual sequences.
382
+
383
+ >> assertSameElements([1, 1, 1, 0, 0, 0], [0, 1])
384
+ # Doesn't raise an AssertionError
385
+
386
+ If possible, you should use assertItemsEqual instead of
387
+ assertSameElements.
388
+
389
+ Args:
390
+ expected_seq: A sequence containing elements we are expecting.
391
+ actual_seq: The sequence that we are testing.
392
+ msg: The message to be printed if the test fails.
393
+ """
394
+ # `unittest2.TestCase` used to have assertSameElements, but it was
395
+ # removed in favor of assertItemsEqual. As there's a unit test
396
+ # that explicitly checks this behavior, I am leaving this method
397
+ # alone.
398
+ try:
399
+ expected = dict([(element, None) for element in expected_seq])
400
+ actual = dict([(element, None) for element in actual_seq])
401
+ missing = [element for element in expected if element not in actual]
402
+ unexpected = [element for element in actual if element not in expected]
403
+ missing.sort()
404
+ unexpected.sort()
405
+ except TypeError:
406
+ # Fall back to slower list-compare if any of the objects are
407
+ # not hashable.
408
+ expected = list(expected_seq)
409
+ actual = list(actual_seq)
410
+ expected.sort()
411
+ actual.sort()
412
+ missing, unexpected = _SortedListDifference(expected, actual)
413
+ errors = []
414
+ if missing:
415
+ errors.append('Expected, but missing:\n %r\n' % missing)
416
+ if unexpected:
417
+ errors.append('Unexpected, but present:\n %r\n' % unexpected)
418
+ if errors:
419
+ self.fail(msg or ''.join(errors))
420
+
421
+ # unittest2.TestCase.assertMulitilineEqual works very similarly, but it
422
+ # has a different error format. However, I find this slightly more readable.
423
+ def assertMultiLineEqual(self, first, second, msg=None):
424
+ """Assert that two multi-line strings are equal."""
425
+ assert isinstance(first, types.StringTypes), (
426
+ 'First argument is not a string: %r' % (first,))
427
+ assert isinstance(second, types.StringTypes), (
428
+ 'Second argument is not a string: %r' % (second,))
429
+
430
+ if first == second:
431
+ return
432
+ if msg:
433
+ raise self.failureException(msg)
434
+
435
+ failure_message = ['\n']
436
+ for line in difflib.ndiff(first.splitlines(True), second.splitlines(True)):
437
+ failure_message.append(line)
438
+ if not line.endswith('\n'):
439
+ failure_message.append('\n')
440
+ raise self.failureException(''.join(failure_message))
441
+
442
+ def assertBetween(self, value, minv, maxv, msg=None):
443
+ """Asserts that value is between minv and maxv (inclusive)."""
444
+ if msg is None:
445
+ msg = '"%r" unexpectedly not between "%r" and "%r"' % (value, minv, maxv)
446
+ self.assert_(minv <= value, msg)
447
+ self.assert_(maxv >= value, msg)
448
+
449
+ def assertRegexMatch(self, actual_str, regexes, message=None):
450
+ """Asserts that at least one regex in regexes matches str.
451
+
452
+ If possible you should use assertRegexpMatches, which is a simpler
453
+ version of this method. assertRegexpMatches takes a single regular
454
+ expression (a string or re compiled object) instead of a list.
455
+
456
+ Notes:
457
+ 1. This function uses substring matching, i.e. the matching
458
+ succeeds if *any* substring of the error message matches *any*
459
+ regex in the list. This is more convenient for the user than
460
+ full-string matching.
461
+
462
+ 2. If regexes is the empty list, the matching will always fail.
463
+
464
+ 3. Use regexes=[''] for a regex that will always pass.
465
+
466
+ 4. '.' matches any single character *except* the newline. To
467
+ match any character, use '(.|\n)'.
468
+
469
+ 5. '^' matches the beginning of each line, not just the beginning
470
+ of the string. Similarly, '$' matches the end of each line.
471
+
472
+ 6. An exception will be thrown if regexes contains an invalid
473
+ regex.
474
+
475
+ Args:
476
+ actual_str: The string we try to match with the items in regexes.
477
+ regexes: The regular expressions we want to match against str.
478
+ See "Notes" above for detailed notes on how this is interpreted.
479
+ message: The message to be printed if the test fails.
480
+ """
481
+ if isinstance(regexes, basestring):
482
+ self.fail('regexes is a string; it needs to be a list of strings.')
483
+ if not regexes:
484
+ self.fail('No regexes specified.')
485
+
486
+ regex = '(?:%s)' % ')|(?:'.join(regexes)
487
+
488
+ if not re.search(regex, actual_str, re.MULTILINE):
489
+ self.fail(message or ('String "%s" does not contain any of these '
490
+ 'regexes: %s.' % (actual_str, regexes)))
491
+
492
+ def assertCommandSucceeds(self, command, regexes=[''], env=None,
493
+ close_fds=True):
494
+ """Asserts that a shell command succeeds (i.e. exits with code 0).
495
+
496
+ Args:
497
+ command: List or string representing the command to run.
498
+ regexes: List of regular expression strings.
499
+ env: Dictionary of environment variable settings.
500
+ close_fds: Whether or not to close all open fd's in the child after
501
+ forking.
502
+ """
503
+ (ret_code, err) = GetCommandStderr(command, env, close_fds)
504
+
505
+ command_string = GetCommandString(command)
506
+ self.assert_(
507
+ ret_code == 0,
508
+ 'Running command\n'
509
+ '%s failed with error code %s and message\n'
510
+ '%s' % (
511
+ _QuoteLongString(command_string),
512
+ ret_code,
513
+ _QuoteLongString(err)))
514
+ self.assertRegexMatch(
515
+ err,
516
+ regexes,
517
+ message=(
518
+ 'Running command\n'
519
+ '%s failed with error code %s and message\n'
520
+ '%s which matches no regex in %s' % (
521
+ _QuoteLongString(command_string),
522
+ ret_code,
523
+ _QuoteLongString(err),
524
+ regexes)))
525
+
526
+ def assertCommandFails(self, command, regexes, env=None, close_fds=True):
527
+ """Asserts a shell command fails and the error matches a regex in a list.
528
+
529
+ Args:
530
+ command: List or string representing the command to run.
531
+ regexes: the list of regular expression strings.
532
+ env: Dictionary of environment variable settings.
533
+ close_fds: Whether or not to close all open fd's in the child after
534
+ forking.
535
+ """
536
+ (ret_code, err) = GetCommandStderr(command, env, close_fds)
537
+
538
+ command_string = GetCommandString(command)
539
+ self.assert_(
540
+ ret_code != 0,
541
+ 'The following command succeeded while expected to fail:\n%s' %
542
+ _QuoteLongString(command_string))
543
+ self.assertRegexMatch(
544
+ err,
545
+ regexes,
546
+ message=(
547
+ 'Running command\n'
548
+ '%s failed with error code %s and message\n'
549
+ '%s which matches no regex in %s' % (
550
+ _QuoteLongString(command_string),
551
+ ret_code,
552
+ _QuoteLongString(err),
553
+ regexes)))
554
+
555
+ def assertRaisesWithPredicateMatch(self, expected_exception, predicate,
556
+ callable_obj, *args,
557
+ **kwargs):
558
+ """Asserts that exception is thrown and predicate(exception) is true.
559
+
560
+ Args:
561
+ expected_exception: Exception class expected to be raised.
562
+ predicate: Function of one argument that inspects the passed-in exception
563
+ and returns True (success) or False (please fail the test).
564
+ callable_obj: Function to be called.
565
+ args: Extra args.
566
+ kwargs: Extra keyword args.
567
+ """
568
+ try:
569
+ callable_obj(*args, **kwargs)
570
+ except expected_exception, err:
571
+ self.assert_(predicate(err),
572
+ '%r does not match predicate %r' % (err, predicate))
573
+ else:
574
+ self.fail(expected_exception.__name__ + ' not raised')
575
+
576
+ def assertRaisesWithLiteralMatch(self, expected_exception,
577
+ expected_exception_message, callable_obj,
578
+ *args, **kwargs):
579
+ """Asserts that the message in a raised exception equals the given string.
580
+
581
+ Unlike assertRaisesWithRegexpMatch this method takes a literal string, not
582
+ a regular expression.
583
+
584
+ Args:
585
+ expected_exception: Exception class expected to be raised.
586
+ expected_exception_message: String message expected in the raised
587
+ exception. For a raise exception e, expected_exception_message must
588
+ equal str(e).
589
+ callable_obj: Function to be called.
590
+ args: Extra args.
591
+ kwargs: Extra kwargs.
592
+ """
593
+ try:
594
+ callable_obj(*args, **kwargs)
595
+ except expected_exception, err:
596
+ actual_exception_message = str(err)
597
+ self.assert_(expected_exception_message == actual_exception_message,
598
+ 'Exception message does not match.\n'
599
+ 'Expected: %r\n'
600
+ 'Actual: %r' % (expected_exception_message,
601
+ actual_exception_message))
602
+ else:
603
+ self.fail(expected_exception.__name__ + ' not raised')
604
+
605
+ def assertRaisesWithRegexpMatch(self, expected_exception, expected_regexp,
606
+ callable_obj, *args, **kwargs):
607
+ """Asserts that the message in a raised exception matches the given regexp.
608
+
609
+ This is just a wrapper around assertRaisesRegexp. Please use
610
+ assertRaisesRegexp instead of assertRaisesWithRegexpMatch.
611
+
612
+ Args:
613
+ expected_exception: Exception class expected to be raised.
614
+ expected_regexp: Regexp (re pattern object or string) expected to be
615
+ found in error message.
616
+ callable_obj: Function to be called.
617
+ args: Extra args.
618
+ kwargs: Extra keyword args.
619
+ """
620
+ # TODO(user): this is a good candidate for a global
621
+ # search-and-replace.
622
+ self.assertRaisesRegexp(
623
+ expected_exception,
624
+ expected_regexp,
625
+ callable_obj,
626
+ *args,
627
+ **kwargs)
628
+
629
+ def assertContainsInOrder(self, strings, target):
630
+ """Asserts that the strings provided are found in the target in order.
631
+
632
+ This may be useful for checking HTML output.
633
+
634
+ Args:
635
+ strings: A list of strings, such as [ 'fox', 'dog' ]
636
+ target: A target string in which to look for the strings, such as
637
+ 'The quick brown fox jumped over the lazy dog'.
638
+ """
639
+ if not isinstance(strings, list):
640
+ strings = [strings]
641
+
642
+ current_index = 0
643
+ last_string = None
644
+ for string in strings:
645
+ index = target.find(str(string), current_index)
646
+ if index == -1 and current_index == 0:
647
+ self.fail("Did not find '%s' in '%s'" %
648
+ (string, target))
649
+ elif index == -1:
650
+ self.fail("Did not find '%s' after '%s' in '%s'" %
651
+ (string, last_string, target))
652
+ last_string = string
653
+ current_index = index
654
+
655
+ def assertTotallyOrdered(self, *groups):
656
+ """Asserts that total ordering has been implemented correctly.
657
+
658
+ For example, say you have a class A that compares only on its attribute x.
659
+ Comparators other than __lt__ are omitted for brevity.
660
+
661
+ class A(object):
662
+ def __init__(self, x, y):
663
+ self.x = xio
664
+ self.y = y
665
+
666
+ def __hash__(self):
667
+ return hash(self.x)
668
+
669
+ def __lt__(self, other):
670
+ try:
671
+ return self.x < other.x
672
+ except AttributeError:
673
+ return NotImplemented
674
+
675
+ assertTotallyOrdered will check that instances can be ordered correctly.
676
+ For example,
677
+
678
+ self.assertTotallyOrdered(
679
+ [None], # None should come before everything else.
680
+ [1], # Integers sort earlier.
681
+ ['foo'], # As do strings.
682
+ [A(1, 'a')],
683
+ [A(2, 'b')], # 2 is after 1.
684
+ [A(2, 'c'), A(2, 'd')], # The second argument is irrelevant.
685
+ [A(3, 'z')])
686
+
687
+ Args:
688
+ groups: A list of groups of elements. Each group of elements is a list
689
+ of objects that are equal. The elements in each group must be less than
690
+ the elements in the group after it. For example, these groups are
691
+ totally ordered: [None], [1], [2, 2], [3].
692
+ """
693
+
694
+ def CheckOrder(small, big):
695
+ """Ensures small is ordered before big."""
696
+ self.assertFalse(small == big,
697
+ '%r unexpectedly equals %r' % (small, big))
698
+ self.assertTrue(small != big,
699
+ '%r unexpectedly equals %r' % (small, big))
700
+ self.assertLess(small, big)
701
+ self.assertFalse(big < small,
702
+ '%r unexpectedly less than %r' % (big, small))
703
+ self.assertLessEqual(small, big)
704
+ self.assertFalse(big <= small,
705
+ '%r unexpectedly less than or equal to %r'
706
+ % (big, small))
707
+ self.assertGreater(big, small)
708
+ self.assertFalse(small > big,
709
+ '%r unexpectedly greater than %r' % (small, big))
710
+ self.assertGreaterEqual(big, small)
711
+ self.assertFalse(small >= big,
712
+ '%r unexpectedly greater than or equal to %r'
713
+ % (small, big))
714
+
715
+ def CheckEqual(a, b):
716
+ """Ensures that a and b are equal."""
717
+ self.assertEqual(a, b)
718
+ self.assertFalse(a != b, '%r unexpectedly equals %r' % (a, b))
719
+ self.assertEqual(hash(a), hash(b),
720
+ 'hash %d of %r unexpectedly not equal to hash %d of %r'
721
+ % (hash(a), a, hash(b), b))
722
+ self.assertFalse(a < b, '%r unexpectedly less than %r' % (a, b))
723
+ self.assertFalse(b < a, '%r unexpectedly less than %r' % (b, a))
724
+ self.assertLessEqual(a, b)
725
+ self.assertLessEqual(b, a)
726
+ self.assertFalse(a > b, '%r unexpectedly greater than %r' % (a, b))
727
+ self.assertFalse(b > a, '%r unexpectedly greater than %r' % (b, a))
728
+ self.assertGreaterEqual(a, b)
729
+ self.assertGreaterEqual(b, a)
730
+
731
+ # For every combination of elements, check the order of every pair of
732
+ # elements.
733
+ for elements in itertools.product(*groups):
734
+ elements = list(elements)
735
+ for index, small in enumerate(elements[:-1]):
736
+ for big in elements[index + 1:]:
737
+ CheckOrder(small, big)
738
+
739
+ # Check that every element in each group is equal.
740
+ for group in groups:
741
+ for a in group:
742
+ CheckEqual(a, a)
743
+ for a, b in itertools.product(group, group):
744
+ CheckEqual(a, b)
745
+
746
+ def getRecordedProperties(self):
747
+ """Return any properties that the user has recorded."""
748
+ return self.__recorded_properties
749
+
750
+ def recordProperty(self, property_name, property_value):
751
+ """Record an arbitrary property for later use.
752
+
753
+ Args:
754
+ property_name: str, name of property to record; must be a valid XML
755
+ attribute name
756
+ property_value: value of property; must be valid XML attribute value
757
+ """
758
+ self.__recorded_properties[property_name] = property_value
759
+
760
+ def _getAssertEqualityFunc(self, first, second):
761
+ try:
762
+ return super(TestCase, self)._getAssertEqualityFunc(first, second)
763
+ except AttributeError:
764
+ # This happens if unittest2.TestCase.__init__ was never run. It
765
+ # usually means that somebody created a subclass just for the
766
+ # assertions and has overriden __init__. "assertTrue" is a safe
767
+ # value that will not make __init__ raise a ValueError (this is
768
+ # a bit hacky).
769
+ test_method = getattr(self, '_testMethodName', 'assertTrue')
770
+ super(TestCase, self).__init__(test_method)
771
+
772
+ return super(TestCase, self)._getAssertEqualityFunc(first, second)
773
+
774
+
775
+ # This is not really needed here, but some unrelated code calls this
776
+ # function.
777
+ # TODO(user): sort it out.
778
+ def _SortedListDifference(expected, actual):
779
+ """Finds elements in only one or the other of two, sorted input lists.
780
+
781
+ Returns a two-element tuple of lists. The first list contains those
782
+ elements in the "expected" list but not in the "actual" list, and the
783
+ second contains those elements in the "actual" list but not in the
784
+ "expected" list. Duplicate elements in either input list are ignored.
785
+
786
+ Args:
787
+ expected: The list we expected.
788
+ actual: The list we actualy got.
789
+ Returns:
790
+ (missing, unexpected)
791
+ missing: items in expected that are not in actual.
792
+ unexpected: items in actual that are not in expected.
793
+ """
794
+ i = j = 0
795
+ missing = []
796
+ unexpected = []
797
+ while True:
798
+ try:
799
+ e = expected[i]
800
+ a = actual[j]
801
+ if e < a:
802
+ missing.append(e)
803
+ i += 1
804
+ while expected[i] == e:
805
+ i += 1
806
+ elif e > a:
807
+ unexpected.append(a)
808
+ j += 1
809
+ while actual[j] == a:
810
+ j += 1
811
+ else:
812
+ i += 1
813
+ try:
814
+ while expected[i] == e:
815
+ i += 1
816
+ finally:
817
+ j += 1
818
+ while actual[j] == a:
819
+ j += 1
820
+ except IndexError:
821
+ missing.extend(expected[i:])
822
+ unexpected.extend(actual[j:])
823
+ break
824
+ return missing, unexpected
825
+
826
+
827
+ # ----------------------------------------------------------------------
828
+ # Functions to compare the actual output of a test to the expected
829
+ # (golden) output.
830
+ #
831
+ # Note: We could just replace the sys.stdout and sys.stderr objects,
832
+ # but we actually redirect the underlying file objects so that if the
833
+ # Python script execs any subprocess, their output will also be
834
+ # redirected.
835
+ #
836
+ # Usage:
837
+ # basetest.CaptureTestStdout()
838
+ # ... do something ...
839
+ # basetest.DiffTestStdout("... path to golden file ...")
840
+ # ----------------------------------------------------------------------
841
+
842
+
843
+ class CapturedStream(object):
844
+ """A temporarily redirected output stream."""
845
+
846
+ def __init__(self, stream, filename):
847
+ self._stream = stream
848
+ self._fd = stream.fileno()
849
+ self._filename = filename
850
+
851
+ # Keep original stream for later
852
+ self._uncaptured_fd = os.dup(self._fd)
853
+
854
+ # Open file to save stream to
855
+ cap_fd = os.open(self._filename,
856
+ os.O_CREAT | os.O_TRUNC | os.O_WRONLY,
857
+ 0600)
858
+
859
+ # Send stream to this file
860
+ self._stream.flush()
861
+ os.dup2(cap_fd, self._fd)
862
+ os.close(cap_fd)
863
+
864
+ def RestartCapture(self):
865
+ """Resume capturing output to a file (after calling StopCapture)."""
866
+ # Original stream fd
867
+ assert self._uncaptured_fd
868
+
869
+ # Append stream to file
870
+ cap_fd = os.open(self._filename,
871
+ os.O_CREAT | os.O_APPEND | os.O_WRONLY,
872
+ 0600)
873
+
874
+ # Send stream to this file
875
+ self._stream.flush()
876
+ os.dup2(cap_fd, self._fd)
877
+ os.close(cap_fd)
878
+
879
+ def StopCapture(self):
880
+ """Remove output redirection."""
881
+ self._stream.flush()
882
+ os.dup2(self._uncaptured_fd, self._fd)
883
+
884
+ def filename(self):
885
+ return self._filename
886
+
887
+ def __del__(self):
888
+ self.StopCapture()
889
+ os.close(self._uncaptured_fd)
890
+ del self._uncaptured_fd
891
+
892
+
893
+ _captured_streams = {}
894
+
895
+
896
+ def _CaptureTestOutput(stream, filename):
897
+ """Redirect an output stream to a file.
898
+
899
+ Args:
900
+ stream: Should be sys.stdout or sys.stderr.
901
+ filename: File where output should be stored.
902
+ """
903
+ assert not _captured_streams.has_key(stream)
904
+ _captured_streams[stream] = CapturedStream(stream, filename)
905
+
906
+
907
+ def _DiffTestOutput(stream, golden_filename):
908
+ """Compare ouput of redirected stream to contents of golden file.
909
+
910
+ Args:
911
+ stream: Should be sys.stdout or sys.stderr.
912
+ golden_filename: Absolute path to golden file.
913
+ """
914
+ assert _captured_streams.has_key(stream)
915
+ cap = _captured_streams[stream]
916
+
917
+ for cap_stream in _captured_streams.itervalues():
918
+ cap_stream.StopCapture()
919
+
920
+ try:
921
+ _Diff(cap.filename(), golden_filename)
922
+ finally:
923
+ # remove the current stream
924
+ del _captured_streams[stream]
925
+ # restore other stream capture
926
+ for cap_stream in _captured_streams.itervalues():
927
+ cap_stream.RestartCapture()
928
+
929
+
930
+ # Public interface
931
+ def CaptureTestStdout(outfile=None):
932
+ if not outfile:
933
+ outfile = os.path.join(FLAGS.test_tmpdir, 'captured.out')
934
+
935
+ _CaptureTestOutput(sys.stdout, outfile)
936
+
937
+
938
+ def CaptureTestStderr(outfile=None):
939
+ if not outfile:
940
+ outfile = os.path.join(FLAGS.test_tmpdir, 'captured.err')
941
+
942
+ _CaptureTestOutput(sys.stderr, outfile)
943
+
944
+
945
+ def DiffTestStdout(golden):
946
+ _DiffTestOutput(sys.stdout, golden)
947
+
948
+
949
+ def DiffTestStderr(golden):
950
+ _DiffTestOutput(sys.stderr, golden)
951
+
952
+
953
+ def StopCapturing():
954
+ while _captured_streams:
955
+ _, cap_stream = _captured_streams.popitem()
956
+ cap_stream.StopCapture()
957
+ del cap_stream
958
+
959
+
960
+ def _WriteTestData(data, filename):
961
+ """Write data into file named filename."""
962
+ fd = os.open(filename, os.O_CREAT | os.O_TRUNC | os.O_WRONLY, 0600)
963
+ os.write(fd, data)
964
+ os.close(fd)
965
+
966
+
967
+ class OutputDifferedError(AssertionError):
968
+ pass
969
+
970
+
971
+ class DiffFailureError(Exception):
972
+ pass
973
+
974
+
975
+ def _Diff(lhs, rhs):
976
+ """Run standard unix 'diff' against two files."""
977
+
978
+ cmd = '${TEST_DIFF:-diff} %s %s' % (commands.mkarg(lhs), commands.mkarg(rhs))
979
+ (status, output) = commands.getstatusoutput(cmd)
980
+ if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 1:
981
+ # diff outputs must be the same as c++ and shell
982
+ raise OutputDifferedError('\nRunning %s\n%s\nTest output differed '
983
+ 'from golden file\n' % (cmd, output))
984
+ elif not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
985
+ raise DiffFailureError('\nRunning %s\n%s\nFailure diffing test output '
986
+ 'with golden file\n' % (cmd, output))
987
+
988
+
989
+ def DiffTestStringFile(data, golden):
990
+ """Diff data agains a golden file."""
991
+ data_file = os.path.join(FLAGS.test_tmpdir, 'provided.dat')
992
+ _WriteTestData(data, data_file)
993
+ _Diff(data_file, golden)
994
+
995
+
996
+ def DiffTestStrings(data1, data2):
997
+ """Diff two strings."""
998
+ data1_file = os.path.join(FLAGS.test_tmpdir, 'provided_1.dat')
999
+ _WriteTestData(data1, data1_file)
1000
+ data2_file = os.path.join(FLAGS.test_tmpdir, 'provided_2.dat')
1001
+ _WriteTestData(data2, data2_file)
1002
+ _Diff(data1_file, data2_file)
1003
+
1004
+
1005
+ def DiffTestFiles(testgen, golden):
1006
+ _Diff(testgen, golden)
1007
+
1008
+
1009
+ def GetCommandString(command):
1010
+ """Returns an escaped string that can be used as a shell command.
1011
+
1012
+ Args:
1013
+ command: List or string representing the command to run.
1014
+ Returns:
1015
+ A string suitable for use as a shell command.
1016
+ """
1017
+ if isinstance(command, types.StringTypes):
1018
+ return command
1019
+ else:
1020
+ return shellutil.ShellEscapeList(command)
1021
+
1022
+
1023
+ def GetCommandStderr(command, env=None, close_fds=True):
1024
+ """Runs the given shell command and returns a tuple.
1025
+
1026
+ Args:
1027
+ command: List or string representing the command to run.
1028
+ env: Dictionary of environment variable settings.
1029
+ close_fds: Whether or not to close all open fd's in the child after forking.
1030
+
1031
+ Returns:
1032
+ Tuple of (exit status, text printed to stdout and stderr by the command).
1033
+ """
1034
+ if env is None: env = {}
1035
+ # Forge needs PYTHON_RUNFILES in order to find the runfiles directory when a
1036
+ # Python executable is run by a Python test. Pass this through from the
1037
+ # parent environment if not explicitly defined.
1038
+ if os.environ.get('PYTHON_RUNFILES') and not env.get('PYTHON_RUNFILES'):
1039
+ env['PYTHON_RUNFILES'] = os.environ['PYTHON_RUNFILES']
1040
+
1041
+ use_shell = isinstance(command, types.StringTypes)
1042
+ process = subprocess.Popen(
1043
+ command,
1044
+ close_fds=close_fds,
1045
+ env=env,
1046
+ shell=use_shell,
1047
+ stderr=subprocess.STDOUT,
1048
+ stdout=subprocess.PIPE)
1049
+ output = process.communicate()[0]
1050
+ exit_status = process.wait()
1051
+ return (exit_status, output)
1052
+
1053
+
1054
+ def _QuoteLongString(s):
1055
+ """Quotes a potentially multi-line string to make the start and end obvious.
1056
+
1057
+ Args:
1058
+ s: A string.
1059
+
1060
+ Returns:
1061
+ The quoted string.
1062
+ """
1063
+ return ('8<-----------\n' +
1064
+ s + '\n' +
1065
+ '----------->8\n')
1066
+
1067
+
1068
+ class TestProgramManualRun(unittest.TestProgram):
1069
+ """A TestProgram which runs the tests manually."""
1070
+
1071
+ def runTests(self, do_run=False):
1072
+ """Run the tests."""
1073
+ if do_run:
1074
+ unittest.TestProgram.runTests(self)
1075
+
1076
+
1077
+ def main(*args, **kwargs):
1078
+ """Executes a set of Python unit tests.
1079
+
1080
+ Usually this function is called without arguments, so the
1081
+ unittest.TestProgram instance will get created with the default settings,
1082
+ so it will run all test methods of all TestCase classes in the __main__
1083
+ module.
1084
+
1085
+ Args:
1086
+ args: Positional arguments passed through to unittest.TestProgram.__init__.
1087
+ kwargs: Keyword arguments passed through to unittest.TestProgram.__init__.
1088
+ """
1089
+ _RunInApp(RunTests, args, kwargs)
1090
+
1091
+
1092
+ def _IsInAppMain():
1093
+ """Returns True iff app.main or app.really_start is active."""
1094
+ f = sys._getframe().f_back
1095
+ app_dict = app.__dict__
1096
+ while f:
1097
+ if f.f_globals is app_dict and f.f_code.co_name in ('run', 'really_start'):
1098
+ return True
1099
+ f = f.f_back
1100
+ return False
1101
+
1102
+
1103
+ class SavedFlag(object):
1104
+ """Helper class for saving and restoring a flag value."""
1105
+
1106
+ def __init__(self, flag):
1107
+ self.flag = flag
1108
+ self.value = flag.value
1109
+ self.present = flag.present
1110
+
1111
+ def RestoreFlag(self):
1112
+ self.flag.value = self.value
1113
+ self.flag.present = self.present
1114
+
1115
+
1116
+ def _RunInApp(function, args, kwargs):
1117
+ """Executes a set of Python unit tests, ensuring app.really_start.
1118
+
1119
+ Most users should call basetest.main() instead of _RunInApp.
1120
+
1121
+ _RunInApp calculates argv to be the command-line arguments of this program
1122
+ (without the flags), sets the default of FLAGS.alsologtostderr to True,
1123
+ then it calls function(argv, args, kwargs), making sure that `function'
1124
+ will get called within app.run() or app.really_start(). _RunInApp does this
1125
+ by checking whether it is called by either app.run() or
1126
+ app.really_start(), or by calling app.really_start() explicitly.
1127
+
1128
+ The reason why app.really_start has to be ensured is to make sure that
1129
+ flags are parsed and stripped properly, and other initializations done by
1130
+ the app module are also carried out, no matter if basetest.run() is called
1131
+ from within or outside app.run().
1132
+
1133
+ If _RunInApp is called from within app.run(), then it will reparse
1134
+ sys.argv and pass the result without command-line flags into the argv
1135
+ argument of `function'. The reason why this parsing is needed is that
1136
+ __main__.main() calls basetest.main() without passing its argv. So the
1137
+ only way _RunInApp could get to know the argv without the flags is that
1138
+ it reparses sys.argv.
1139
+
1140
+ _RunInApp changes the default of FLAGS.alsologtostderr to True so that the
1141
+ test program's stderr will contain all the log messages unless otherwise
1142
+ specified on the command-line. This overrides any explicit assignment to
1143
+ FLAGS.alsologtostderr by the test program prior to the call to _RunInApp()
1144
+ (e.g. in __main__.main).
1145
+
1146
+ Please note that _RunInApp (and the function it calls) is allowed to make
1147
+ changes to kwargs.
1148
+
1149
+ Args:
1150
+ function: basetest.RunTests or a similar function. It will be called as
1151
+ function(argv, args, kwargs) where argv is a list containing the
1152
+ elements of sys.argv without the command-line flags.
1153
+ args: Positional arguments passed through to unittest.TestProgram.__init__.
1154
+ kwargs: Keyword arguments passed through to unittest.TestProgram.__init__.
1155
+ """
1156
+ if _IsInAppMain():
1157
+ # Save command-line flags so the side effects of FLAGS(sys.argv) can be
1158
+ # undone.
1159
+ saved_flags = dict((f.name, SavedFlag(f))
1160
+ for f in FLAGS.FlagDict().itervalues())
1161
+
1162
+ # Here we'd like to change the default of alsologtostderr from False to
1163
+ # True, so the test programs's stderr will contain all the log messages.
1164
+ # The desired effect is that if --alsologtostderr is not specified in
1165
+ # the command-line, and __main__.main doesn't set FLAGS.logtostderr
1166
+ # before calling us (basetest.main), then our changed default takes
1167
+ # effect and alsologtostderr becomes True.
1168
+ #
1169
+ # However, we cannot achive this exact effect, because here we cannot
1170
+ # distinguish these situations:
1171
+ #
1172
+ # A. main.__main__ has changed it to False, it hasn't been specified on
1173
+ # the command-line, and the default was kept as False. We should keep
1174
+ # it as False.
1175
+ #
1176
+ # B. main.__main__ hasn't changed it, it hasn't been specified on the
1177
+ # command-line, and the default was kept as False. We should change
1178
+ # it to True here.
1179
+ #
1180
+ # As a workaround, we assume that main.__main__ never changes
1181
+ # FLAGS.alsologstderr to False, thus the value of the flag is determined
1182
+ # by its default unless the command-line overrides it. We want to change
1183
+ # the default to True, and we do it by setting the flag value to True, and
1184
+ # letting the command-line override it in FLAGS(sys.argv) below by not
1185
+ # restoring it in saved_flag.RestoreFlag().
1186
+ if 'alsologtostderr' in saved_flags:
1187
+ FLAGS.alsologtostderr = True
1188
+ del saved_flags['alsologtostderr']
1189
+
1190
+ # The call FLAGS(sys.argv) parses sys.argv, returns the arguments
1191
+ # without the flags, and -- as a side effect -- modifies flag values in
1192
+ # FLAGS. We don't want the side effect, because we don't want to
1193
+ # override flag changes the program did (e.g. in __main__.main)
1194
+ # after the command-line has been parsed. So we have the for loop below
1195
+ # to change back flags to their old values.
1196
+ argv = FLAGS(sys.argv)
1197
+ for saved_flag in saved_flags.itervalues():
1198
+ saved_flag.RestoreFlag()
1199
+
1200
+
1201
+ function(argv, args, kwargs)
1202
+ else:
1203
+ # Send logging to stderr. Use --alsologtostderr instead of --logtostderr
1204
+ # in case tests are reading their own logs.
1205
+ if 'alsologtostderr' in FLAGS:
1206
+ FLAGS.SetDefault('alsologtostderr', True)
1207
+
1208
+ def Main(argv):
1209
+ function(argv, args, kwargs)
1210
+
1211
+ app.really_start(main=Main)
1212
+
1213
+
1214
+ def RunTests(argv, args, kwargs):
1215
+ """Executes a set of Python unit tests within app.really_start.
1216
+
1217
+ Most users should call basetest.main() instead of RunTests.
1218
+
1219
+ Please note that RunTests should be called from app.really_start (which is
1220
+ called from app.run()). Calling basetest.main() would ensure that.
1221
+
1222
+ Please note that RunTests is allowed to make changes to kwargs.
1223
+
1224
+ Args:
1225
+ argv: sys.argv with the command-line flags removed from the front, i.e. the
1226
+ argv with which app.run() has called __main__.main.
1227
+ args: Positional arguments passed through to unittest.TestProgram.__init__.
1228
+ kwargs: Keyword arguments passed through to unittest.TestProgram.__init__.
1229
+ """
1230
+ test_runner = kwargs.get('testRunner')
1231
+
1232
+ # Make sure tmpdir exists
1233
+ if not os.path.isdir(FLAGS.test_tmpdir):
1234
+ os.makedirs(FLAGS.test_tmpdir)
1235
+
1236
+ # Run main module setup, if it exists
1237
+ main_mod = sys.modules['__main__']
1238
+ if hasattr(main_mod, 'setUp') and callable(main_mod.setUp):
1239
+ main_mod.setUp()
1240
+
1241
+ # Let unittest.TestProgram.__init__ called by
1242
+ # TestProgramManualRun.__init__ do its own argv parsing, e.g. for '-v',
1243
+ # on argv, which is sys.argv without the command-line flags.
1244
+ kwargs.setdefault('argv', argv)
1245
+
1246
+ try:
1247
+ result = None
1248
+ test_program = TestProgramManualRun(*args, **kwargs)
1249
+ if test_runner:
1250
+ test_program.testRunner = test_runner
1251
+ else:
1252
+ test_program.testRunner = unittest.TextTestRunner(
1253
+ verbosity=test_program.verbosity)
1254
+ result = test_program.testRunner.run(test_program.test)
1255
+ finally:
1256
+ # Run main module teardown, if it exists
1257
+ if hasattr(main_mod, 'tearDown') and callable(main_mod.tearDown):
1258
+ main_mod.tearDown()
1259
+
1260
+ sys.exit(not result.wasSuccessful())