Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(274)

Side by Side Diff: third_party/gsutil/gslib/commands/test.py

Issue 10199002: Upgrade gsutil to 3.4 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed comments Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright 2011 Google Inc.
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 import subprocess
16 import unittest
17 import os
18 import re
19 import getpass
20 import platform
21
22 from gslib.command import Command
23 from gslib.command import COMMAND_NAME
24 from gslib.command import COMMAND_NAME_ALIASES
25 from gslib.command import CONFIG_REQUIRED
26 from gslib.command import FILE_URIS_OK
27 from gslib.command import MAX_ARGS
28 from gslib.command import MIN_ARGS
29 from gslib.command import PROVIDER_URIS_OK
30 from gslib.command import SUPPORTED_SUB_ARGS
31 from gslib.command import URIS_START_ARG
32 from gslib.exception import CommandException
33 from gslib.help_provider import HELP_NAME
34 from gslib.help_provider import HELP_NAME_ALIASES
35 from gslib.help_provider import HELP_ONE_LINE_SUMMARY
36 from gslib.help_provider import HELP_TEXT
37 from gslib.help_provider import HelpType
38 from gslib.help_provider import HELP_TYPE
39 from gslib.util import NO_MAX
40 from tests.s3.mock_storage_service import MockBucketStorageUri
41
42 _detailed_help_text = ("""
43 <B>SYNOPSIS</B>
44 gsutil test [command command...]
45
46
47 <B>DESCRIPTION</B>
48 The gsutil test command runs end-to-end tests of gsutil commands (i.e.,
49 tests that send requests to the production service. This stands in contrast
50 to tests that use an in-memory mock storage service implementation (see
51 "gsutil help dev" for more details on the latter).
52
53 To run all end-to-end tests run the command with no arguments:
54
55 gsutil test
56
57 To see additional details for test failures:
58
59 gsutil -d test
60
61 To run tests for one or more individual commands add those commands as
62 arguments. For example:
63
64 gsutil test cp mv
65
66 will run the cp and mv command tests.
67
68 Note: the end-to-end tests are defined in the code for each command (e.g.,
69 cp end-to-end tests are in gslib/commands/cp.py). See the comments around
70 'test_steps' in each of the Command subclasses.
71 """)
72
73
74 class TestCommand(Command):
75 """Implementation of gsutil test command."""
76
77 # Command specification (processed by parent class).
78 command_spec = {
79 # Name of command.
80 COMMAND_NAME : 'test',
81 # List of command name aliases.
82 COMMAND_NAME_ALIASES : [],
83 # Min number of args required by this command.
84 MIN_ARGS : 0,
85 # Max number of args required by this command, or NO_MAX.
86 MAX_ARGS : NO_MAX,
87 # Getopt-style string specifying acceptable sub args.
88 SUPPORTED_SUB_ARGS : '',
89 # True if file URIs acceptable for this command.
90 FILE_URIS_OK : True,
91 # True if provider-only URIs acceptable for this command.
92 PROVIDER_URIS_OK : False,
93 # Index in args of first URI arg.
94 URIS_START_ARG : 0,
95 # True if must configure gsutil before running command.
96 CONFIG_REQUIRED : True,
97 }
98 help_spec = {
99 # Name of command or auxiliary help info for which this help applies.
100 HELP_NAME : 'test',
101 # List of help name aliases.
102 HELP_NAME_ALIASES : [],
103 # Type of help:
104 HELP_TYPE : HelpType.COMMAND_HELP,
105 # One line summary of this help.
106 HELP_ONE_LINE_SUMMARY : 'Run end to end gsutil tests',
107 # The full help text.
108 HELP_TEXT : _detailed_help_text,
109 }
110
111 # Define constants & class attributes for command testing.
112 username = getpass.getuser().lower()
113 _test_prefix_file = 'gsutil_test_file_' + username + '_'
114 _test_prefix_bucket = 'gsutil_test_bucket_' + username + '_'
115 _test_prefix_object = 'gsutil_test_object_' + username + '_'
116 # Replacement regexps for format specs in test_steps values.
117 _test_replacements = {
118 r'\$B(\d)' : _test_prefix_bucket + r'\1',
119 r'\$O(\d)' : _test_prefix_object + r'\1',
120 r'\$F(\d)' : _test_prefix_file + r'\1',
121 }
122
123 def _TestRunner(self, cmd, debug):
124 """Run a test command in a subprocess and return result. If debugging
125 requested, display the command, otherwise redirect stdout & stderr
126 to /dev/null.
127 """
128 if not debug and '>' not in cmd:
129 cmd += ' >/dev/null 2>&1'
130 if debug:
131 print 'cmd:', cmd
132 return subprocess.call(cmd, shell=True)
133
134 def global_setup(self, debug):
135 """General test setup.
136
137 For general testing use create three buckets, one empty, one
138 containing one object and one containing two objects. Also create
139 three files for general use.
140 """
141 print 'Global setup started...'
142
143 # Build lists of buckets and files.
144 bucket_list = ['gs://$B%d' % i for i in range(0, 10)]
145 file_list = ['$F%d' % i for i in range(0, 3)]
146
147 # Create test buckets.
148 bucket_cmd = self.gsutil_cmd + ' mb ' + ' '.join(bucket_list)
149 bucket_cmd = self.sub_format_specs(bucket_cmd)
150 self._TestRunner(bucket_cmd, debug)
151
152 # Create test objects - zero in first bucket, one in second, two in third.
153 for i in range(0, 3):
154 for j in range(0, i):
155 object_cmd = 'echo test | ' + self.gsutil_cmd + \
156 ' cp - gs://$B%d/$O%d' % (i, j)
157 object_cmd = self.sub_format_specs(object_cmd)
158 self._TestRunner(object_cmd, debug)
159
160 # Create three test files of size 10MB each.
161 for file in file_list:
162 file = self.sub_format_specs(file)
163 f = open(file, 'w')
164 f.write(os.urandom(10**6))
165 f.close()
166
167 print 'Global setup completed.'
168
169 def global_teardown(self, debug):
170 """General test cleanup.
171
172 Remove all buckets, objects and files used by this test facility.
173 """
174 print 'Global teardown started...'
175 # Build commands to remove objects, buckets and files.
176 bucket_list = ['gs://$B%d' % i for i in range(0, 10)]
177 object_list = ['gs://$B%d/*' % i for i in range(0, 10)]
178 file_list = ['$F%d' % i for i in range(0, 10)]
179 bucket_cmd = self.gsutil_cmd + ' rb ' + ' '.join(bucket_list)
180 object_cmd = self.gsutil_cmd + ' rm -f ' + ' '.join(object_list)
181 for f in file_list:
182 f = self.sub_format_specs(f)
183 if os.path.exists(f):
184 os.unlink(f)
185
186 # Substitute format specifiers ($Bn, $On, $Fn).
187 bucket_cmd = self.sub_format_specs(bucket_cmd)
188 if not debug:
189 bucket_cmd += ' >/dev/null 2>&1'
190 object_cmd = self.sub_format_specs(object_cmd)
191 if not debug:
192 object_cmd += ' >/dev/null 2>&1'
193
194 # Run the commands.
195 self._TestRunner(object_cmd, debug)
196 self._TestRunner(bucket_cmd, debug)
197
198 print 'Global teardown completed.'
199
200 # Command entry point.
201 def RunCommand(self):
202
203 # To avoid testing aliases, we keep track of previous tests.
204 already_tested = {}
205
206 self.gsutil_cmd = ''
207 # If running on Windows, invoke python interpreter explicitly.
208 if platform.system() == "Windows":
209 self.gsutil_cmd += 'python '
210 # Add full path to gsutil to make sure we test the correct version.
211 self.gsutil_cmd += os.path.join(self.gsutil_bin_dir, 'gsutil')
212
213 # Set sim option on exec'ed commands if user requested mock provider.
214 if issubclass(self.bucket_storage_uri_class, MockBucketStorageUri):
215 self.gsutil_cmd += ' -s'
216
217 # Instantiate test generator for creating test functions on the fly.
218 gen = test_generator()
219
220 # Set list of commands to test to include user supplied commands or all
221 # commands if none specified by user ('gsutil test' implies test all).
222 commands_to_test = []
223 if self.args:
224 for name in self.args:
225 if name in self.command_runner.command_map:
226 commands_to_test.append(name)
227 else:
228 raise CommandException('Test requested for unknown command %s.'
229 % name)
230 else:
231 # No commands specified so test all commands.
232 commands_to_test = self.command_runner.command_map.keys()
233
234 for name in commands_to_test:
235 cmd = self.command_runner.command_map[name]
236
237 # Skip this command if test steps not defined or empty.
238 if not hasattr(cmd, 'test_steps') or not cmd.test_steps:
239 if self.debug:
240 print 'Skipping %s command because no test steps defined.' % name
241 continue
242
243 # Skip aliases for commands we've already tested.
244 if cmd in already_tested:
245 continue
246 already_tested[cmd] = 1
247
248 # Run global test setup.
249 self.global_setup(self.debug)
250
251 # If command has a test_setup method, run per command setup here.
252 if hasattr(cmd, 'test_setup'):
253 cmd.test_setup(self.debug)
254
255 # Instantiate a test suite, which we'll dynamically add tests to.
256 suite = unittest.TestSuite()
257
258 # Iterate over the entries in this command's test specification.
259 for (cmdname, cmdline, expect_ret, diff) in cmd.test_steps:
260 cmdline = cmdline.replace('gsutil ', self.gsutil_cmd + ' ')
261 if platform.system() == 'Windows':
262 cmdline = cmdline.replace('cat ', 'type ')
263
264 # Store file names requested for diff.
265 result_file = None
266 expect_file = None
267 if diff:
268 (result_file, expect_file) = diff
269
270 # Substitute format specifiers ($Bn, $On, $Fn).
271 cmdline = self.sub_format_specs(cmdline)
272 result_file = self.sub_format_specs(result_file)
273 expect_file = self.sub_format_specs(expect_file)
274
275 # Generate test function, wrap in a test case and add to test suite.
276 func = gen.genTest(self._TestRunner, cmdline, expect_ret,
277 result_file, expect_file, self.debug)
278 test_case = unittest.FunctionTestCase(func, description=cmdname)
279 suite.addTest(test_case)
280
281 # Run the tests we've just accumulated.
282 print 'Running tests for', name, 'command.'
283 unittest.TextTestRunner(verbosity=2).run(suite)
284
285 # If command has a test_teardown method, run per command teardown here.
286 if hasattr(cmd, 'test_teardown'):
287 cmd.test_teardown(self.debug)
288
289 # Run global test teardown.
290 self.global_teardown(self.debug)
291
292 def sub_format_specs(self, s):
293 """Perform iterative regexp substitutions on passed string.
294
295 This method iteratively substitutes values in a passed string,
296 returning the modified string when done.
297 """
298 # Don't bother if the passed string is empty or None.
299 if s:
300 for (template, repl_str) in self._test_replacements.items():
301 while re.search(template, s):
302 # Keep substituting as long as the template is found.
303 s = re.sub(template, repl_str, s)
304 return s
305
306
307 class test_generator(unittest.TestCase):
308 """Dynamic test generator for use with unittest module.
309
310 This class is used to generate a test case function. It
311 inherits from unittest.TestCase so that it has access to
312 all the TestCase componentry (e.g. self.assertEqual, etc.).
313 """
314
315 def runTest():
316 """Required method to instantiate unittest.TestCase derived class."""
317 pass
318
319 def genTest(self, runner, cmd, expect_ret, result_file, expect_file, debug):
320 """Create and return a function to execute unittest module test cases.
321
322 This method generates a test function based on the passed
323 input and some inherited methods and returns the generated
324 function to the caller.
325 """
326
327 def test_func():
328 # Run the test command and capture the result in ret.
329 ret = runner(cmd, debug)
330 if expect_ret is not None:
331 # If an expected return code was passed, make sure we got it.
332 self.assertEqual(ret, expect_ret)
333 if result_file and expect_file:
334 # If cmd generated output, diff it against expected output.
335 if platform.system() == 'Windows':
336 diff_cmd = 'echo n | comp '
337 else:
338 diff_cmd = 'diff '
339 diff_cmd += '%s %s' % (result_file, expect_file)
340 diff_ret = runner(diff_cmd, debug)
341 self.assertEqual(diff_ret, 0)
342 # Return the generated function to the caller.
343 return test_func
344
OLDNEW
« no previous file with comments | « third_party/gsutil/gslib/commands/setdefacl.py ('k') | third_party/gsutil/gslib/commands/update.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698