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,1651 @@
1
+ #!/usr/bin/python
2
+ #
3
+ # Copyright 2012 Google Inc. All Rights Reserved.
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
+ """Unit tests for the base command classes."""
18
+
19
+ from __future__ import with_statement
20
+
21
+
22
+
23
+ import path_initializer
24
+ path_initializer.InitializeSysPath()
25
+
26
+ import copy
27
+ import datetime
28
+ import os
29
+ import sys
30
+ import tempfile
31
+
32
+
33
+
34
+
35
+ from google.apputils import app
36
+ import gflags as flags
37
+ import unittest
38
+
39
+ from gcutil import command_base
40
+ from gcutil import gcutil_logging
41
+ from gcutil import mock_api
42
+
43
+ FLAGS = flags.FLAGS
44
+
45
+
46
+ class CommandBaseTest(unittest.TestCase):
47
+
48
+ class ListMockCommandBase(command_base.GoogleComputeListCommand):
49
+ """A list mock command that specifies no default sort field."""
50
+
51
+ summary_fields = (('name', 'id'),
52
+ ('id', 'number'),
53
+ ('description', 'description'))
54
+
55
+ def __init__(self, name, flag_values):
56
+ super(CommandBaseTest.ListMockCommandBase, self).__init__(
57
+ name, flag_values)
58
+
59
+ def SetApi(self, api):
60
+ pass
61
+
62
+ def ListFunc(self):
63
+
64
+ def Func(project=None, maxResults=None, filter=None, pageToken=None):
65
+ return mock_api.MockRequest(
66
+ {'items': [{'description': 'Object C',
67
+ 'id': 'projects/user/objects/my-object-c',
68
+ 'kind': 'cloud#object',
69
+ 'number': 123},
70
+ {'description': 'Object A',
71
+ 'id': 'projects/user/objects/my-object-a',
72
+ 'kind': 'cloud#object',
73
+ 'number': 789},
74
+ {'description': 'Object B',
75
+ 'id': 'projects/user/objects/my-object-b',
76
+ 'kind': 'cloud#object',
77
+ 'number': 456},
78
+ {'description': 'Object D',
79
+ 'id': 'projects/user/objects/my-object-d',
80
+ 'kind': 'cloud#object',
81
+ 'number': 999}],
82
+ 'kind': 'cloud#objectList'})
83
+
84
+ return Func
85
+
86
+ class ListMockCommand(ListMockCommandBase):
87
+ """A list mock command that specifies a default sort field."""
88
+ default_sort_field = 'name'
89
+
90
+ def __init__(self, name, flag_values):
91
+ super(CommandBaseTest.ListMockCommand, self).__init__(name, flag_values)
92
+
93
+ class MockDetailCommand(command_base.GoogleComputeCommand):
94
+
95
+ detail_fields = (('name', 'id'),
96
+ ('id', 'number'),
97
+ ('description', 'description'),
98
+ ('additional', 'moreStuff'))
99
+
100
+ def __init__(self, name, flag_values):
101
+ super(CommandBaseTest.MockDetailCommand, self).__init__(name, flag_values)
102
+
103
+ def SetApi(self, api):
104
+ pass
105
+
106
+ def Handle(self):
107
+ return {'description': 'Object C',
108
+ 'id': 'projects/user/objects/my-object-c',
109
+ 'kind': 'cloud#object',
110
+ 'number': 123,
111
+ 'moreStuff': 'foo'}
112
+
113
+ class MockSafetyCommand(command_base.GoogleComputeCommand):
114
+
115
+ safety_prompt = 'Take scary action'
116
+
117
+ def __init__(self, name, flag_values):
118
+ super(CommandBaseTest.MockSafetyCommand, self).__init__(name, flag_values)
119
+
120
+ def SetApi(self, api):
121
+ pass
122
+
123
+ def Handle(self):
124
+ pass
125
+
126
+ class MockSafetyCommandWithArgs(MockSafetyCommand):
127
+ safety_prompt = 'Act on'
128
+
129
+ def Handle(self, argument, arg2):
130
+ pass
131
+
132
+ class FakeExit(object):
133
+ """A fake version of exit to capture exit status."""
134
+
135
+ def __init__(self):
136
+ self.__status__ = []
137
+
138
+ def __call__(self, value):
139
+ self.__status__.append(value)
140
+
141
+ def GetStatuses(self):
142
+ return self.__status__
143
+
144
+ class CaptureOutput(object):
145
+
146
+ def __init__(self):
147
+ self._capture_text = ''
148
+
149
+ # Purposefully name this 'write' to mock an output stream
150
+ # pylint: disable-msg=C6409
151
+ def write(self, text):
152
+ self._capture_text += text
153
+
154
+ # Purposefully name this 'flush' to mock an output stream
155
+ # pylint: disable-msg=C6409
156
+ def flush(self):
157
+ pass
158
+
159
+ def GetCapturedText(self):
160
+ return self._capture_text
161
+
162
+ class MockInput(object):
163
+
164
+ def __init__(self, input_string):
165
+ self._input_string = input_string
166
+
167
+ # Purposefully name this 'readline' to mock an input stream
168
+ # pylint: disable-msg=C6409
169
+ def readline(self):
170
+ return self._input_string
171
+
172
+ def ClearLogger(self):
173
+ for h in gcutil_logging.LOGGER.handlers:
174
+ gcutil_logging.LOGGER.removeHandler(h)
175
+
176
+ def test_PresentElement(self):
177
+ class MockCommand(command_base.GoogleComputeCommand):
178
+ def __init__(self, name, flag_values):
179
+ super(MockCommand, self).__init__(name, flag_values)
180
+
181
+ flag_values = copy.deepcopy(FLAGS)
182
+ command = MockCommand('mock_command', flag_values)
183
+ flag_values.project = 'user'
184
+ flag_values.service_version = 'v1beta13'
185
+ command.SetFlags(flag_values)
186
+
187
+ self.assertEqual(
188
+ 'user',
189
+ command._PresentElement('https://www.googleapis.com/compute/v1/'
190
+ 'projects/user'))
191
+ self.assertEqual(
192
+ 'user',
193
+ command._PresentElement('https://www.googleapis.com/compute/v1/'
194
+ 'projects/user/'))
195
+ self.assertEqual('user', command._PresentElement('projects/user'))
196
+ self.assertEqual('user', command._PresentElement('projects/user/'))
197
+ self.assertEqual(
198
+ 'standard-2-cpu',
199
+ command._PresentElement('https://www.googleapis.com/compute/v1/'
200
+ 'projects/user/machine-types/standard-2-cpu'))
201
+ self.assertEqual(
202
+ 'standard-2-cpu',
203
+ command._PresentElement('https://www.googleapis.com/compute/v1/'
204
+ 'projects/user/machine-types/standard-2-cpu/'))
205
+ self.assertEqual(
206
+ 'standard-2-cpu',
207
+ command._PresentElement('projects/user/machine-types/standard-2-cpu'))
208
+ self.assertEqual(
209
+ 'standard-2-cpu',
210
+ command._PresentElement('projects/user/machine-types/standard-2-cpu/'))
211
+ self.assertEqual(
212
+ 'foo/bar/baz',
213
+ command._PresentElement('https://www.googleapis.com/compute/v1/'
214
+ 'projects/user/shared-fate-zones/foo/bar/baz'))
215
+ self.assertEqual(
216
+ 'foo/bar/baz',
217
+ command._PresentElement('projects/user/shared-fate-zones/foo/bar/baz'))
218
+ self.assertEqual('foo/bar/baz', command._PresentElement('foo/bar/baz'))
219
+
220
+ # Tests eliding feature
221
+ test_str = ('I am the very model of a modern Major-General. I\'ve '
222
+ 'information vegetable, animal, and mineral. I know the kings '
223
+ 'of England and quote the fights historical; from Marathon to '
224
+ 'Waterloo in order categorical.')
225
+ self.assertEqual(
226
+ 'I am the very model of a modern.. Waterloo in order categorical.',
227
+ command._PresentElement(test_str))
228
+
229
+ flag_values.long_values_display_format = 'full'
230
+ command.SetFlags(flag_values)
231
+ self.assertEqual(test_str, command._PresentElement(test_str))
232
+
233
+ def testDenormalizeProjectName(self):
234
+ denormalize = command_base.GoogleComputeCommand.DenormalizeProjectName
235
+ flag_values = flags.FlagValues()
236
+ flags.DEFINE_string('project',
237
+ None,
238
+ 'Project Name',
239
+ flag_values=flag_values)
240
+ flags.DEFINE_string('project_id',
241
+ None,
242
+ 'Obsolete Project Name',
243
+ flag_values=flag_values)
244
+
245
+ self.assertRaises(command_base.CommandError,
246
+ denormalize,
247
+ flag_values)
248
+
249
+ flag_values.project = 'project_collection/google'
250
+ self.assertRaises(command_base.CommandError,
251
+ denormalize,
252
+ flag_values)
253
+
254
+ flag_values.project = 'projects/google'
255
+ denormalize(flag_values)
256
+ self.assertEqual(flag_values.project, 'google')
257
+ denormalize(flag_values)
258
+ self.assertEqual(flag_values.project, 'google')
259
+
260
+ flag_values.project = '/google'
261
+ denormalize(flag_values)
262
+ self.assertEqual(flag_values.project, 'google')
263
+
264
+ flag_values.project = 'google/'
265
+ denormalize(flag_values)
266
+ self.assertEqual(flag_values.project, 'google')
267
+
268
+ flag_values.project = '/google/'
269
+ denormalize(flag_values)
270
+ self.assertEqual(flag_values.project, 'google')
271
+
272
+ flag_values.project = '/projects/google'
273
+ denormalize(flag_values)
274
+ self.assertEqual(flag_values.project, 'google')
275
+
276
+ flag_values.project = 'projects/google/'
277
+ denormalize(flag_values)
278
+ self.assertEqual(flag_values.project, 'google')
279
+
280
+ flag_values.project = '/projects/google/'
281
+ denormalize(flag_values)
282
+ self.assertEqual(flag_values.project, 'google')
283
+
284
+ flag_values.project_id = 'my-obsolete-project-1'
285
+ flag_values.project = 'my-new-project-1'
286
+ denormalize(flag_values)
287
+ self.assertEqual(flag_values.project, 'my-new-project-1')
288
+ self.assertEqual(flag_values.project_id, None)
289
+
290
+ flag_values.project_id = 'my-new-project-2'
291
+ flag_values.project = None
292
+ denormalize(flag_values)
293
+ self.assertEqual(flag_values.project, 'my-new-project-2')
294
+ self.assertEqual(flag_values.project_id, None)
295
+
296
+ flag_values.project_id = 'MyUppercaseProject-1'
297
+ flag_values.project = None
298
+ self.assertRaises(command_base.CommandError, denormalize, flag_values)
299
+
300
+ flag_values.project = 'MyUppercaseProject-2'
301
+ flag_values.project_id = None
302
+ self.assertRaises(command_base.CommandError, denormalize, flag_values)
303
+
304
+ def testDenormalizeResourceName(self):
305
+ denormalize = command_base.GoogleComputeCommand.DenormalizeResourceName
306
+ self.assertEqual('dual-cpu',
307
+ denormalize('projects/google/machine_types/dual-cpu'))
308
+ self.assertEqual('dual-cpu',
309
+ denormalize('/projects/google/machine_types/dual-cpu'))
310
+ self.assertEqual('dual-cpu',
311
+ denormalize('projects/google/machine_types/dual-cpu/'))
312
+ self.assertEqual('dual-cpu',
313
+ denormalize('/projects/google/machine_types/dual-cpu/'))
314
+ self.assertEqual('dual-cpu',
315
+ denormalize('//projects/google/machine_types/dual-cpu//'))
316
+ self.assertEqual('dual-cpu',
317
+ denormalize('dual-cpu'))
318
+ self.assertEqual('dual-cpu',
319
+ denormalize('/dual-cpu'))
320
+ self.assertEqual('dual-cpu',
321
+ denormalize('dual-cpu/'))
322
+ self.assertEqual('dual-cpu',
323
+ denormalize('/dual-cpu/'))
324
+
325
+ def _DoTestNormalizeResourceName(self, service_version):
326
+ class MockCommand(command_base.GoogleComputeCommand):
327
+ def __init__(self, name, flag_values):
328
+ super(MockCommand, self).__init__(name, flag_values)
329
+
330
+ flag_values = copy.deepcopy(FLAGS)
331
+ flag_values.project = 'google'
332
+ flag_values.service_version = service_version
333
+
334
+ command = MockCommand('mock_command', flag_values)
335
+ command.SetFlags(flag_values)
336
+
337
+ prefix = 'https://www.googleapis.com/compute/%s' % service_version
338
+ expected = '%s/projects/google/machine_types/dual-cpu' % prefix
339
+
340
+ self.assertEqual(
341
+ expected,
342
+ command.NormalizeResourceName('google', None, 'machine_types',
343
+ 'dual-cpu'))
344
+ self.assertEqual(
345
+ expected,
346
+ command.NormalizeResourceName('google', None, 'machine_types',
347
+ '/dual-cpu'))
348
+ self.assertEqual(
349
+ expected,
350
+ command.NormalizeResourceName('google', None, 'machine_types',
351
+ 'dual-cpu/'))
352
+ self.assertEqual(
353
+ expected,
354
+ command.NormalizeResourceName('google', None, 'machine_types',
355
+ '/dual-cpu/'))
356
+ self.assertEqual(
357
+ expected,
358
+ command.NormalizeResourceName(
359
+ 'google',
360
+ None,
361
+ 'machine_types',
362
+ 'projects/google/machine_types/dual-cpu'))
363
+ self.assertEqual(
364
+ expected,
365
+ command.NormalizeResourceName(
366
+ 'google',
367
+ None,
368
+ 'machine_types',
369
+ '/projects/google/machine_types/dual-cpu'))
370
+ self.assertEqual(
371
+ expected,
372
+ command.NormalizeResourceName(
373
+ 'google',
374
+ None,
375
+ 'machine_types',
376
+ 'projects/google/machine_types/dual-cpu/'))
377
+ self.assertEqual(
378
+ expected,
379
+ command.NormalizeResourceName(
380
+ 'google',
381
+ None,
382
+ 'machine_types',
383
+ '/projects/google/machine_types/dual-cpu/'))
384
+ self.assertEqual(
385
+ '%s/projects/google/kernels/default' % prefix,
386
+ command.NormalizeResourceName(
387
+ 'my-project',
388
+ None,
389
+ 'kernels',
390
+ 'projects/google/kernels/default'))
391
+
392
+ def testNormalizeResourceName(self):
393
+ for version in command_base.SUPPORTED_VERSIONS:
394
+ self._DoTestNormalizeResourceName(version)
395
+
396
+ def testNormalizeScopedResourceName(self):
397
+ class MockCommand(command_base.GoogleComputeCommand):
398
+ def __init__(self, name, flag_values):
399
+ super(MockCommand, self).__init__(name, flag_values)
400
+
401
+ flag_values = copy.deepcopy(FLAGS)
402
+ flag_values.project = 'my-project'
403
+
404
+ command = MockCommand('mock_command', flag_values)
405
+ command.SetFlags(flag_values)
406
+
407
+ # Validate scope is ignored downlevel
408
+ flag_values.service_version = 'v1beta13'
409
+ prefix = 'https://www.googleapis.com/compute/v1beta13'
410
+ expected = '%s/projects/my-project/objects/foo-bar' % prefix
411
+ self.assertEqual(
412
+ expected,
413
+ command.NormalizeResourceName('my-project', 'scope', 'objects',
414
+ 'foo-bar'))
415
+
416
+ # Validate scope is expected in v1beta14 and above
417
+ flag_values.service_version = 'v1beta14'
418
+ prefix = 'https://www.googleapis.com/compute/v1beta14'
419
+
420
+ expected = '%s/projects/my-project/scope/objects/foo-bar' % prefix
421
+ self.assertEqual(
422
+ expected,
423
+ command.NormalizeResourceName('my-project', 'scope', 'objects',
424
+ 'foo-bar'))
425
+
426
+ # Validate helper wrappers
427
+ expected = '%s/projects/my-project/objects/foo-bar' % prefix
428
+ self.assertEqual(
429
+ expected,
430
+ command.NormalizeTopLevelResourceName('my-project', 'objects',
431
+ 'foo-bar'))
432
+
433
+ expected = '%s/projects/my-project/global/objects/foo-bar' % prefix
434
+ self.assertEqual(
435
+ expected,
436
+ command.NormalizeGlobalResourceName('my-project', 'objects',
437
+ 'foo-bar'))
438
+
439
+ expected = '%s/projects/my-project/zones/zone-a/objects/foo-bar' % prefix
440
+ self.assertEqual(
441
+ expected,
442
+ command.NormalizePerZoneResourceName('my-project', 'zone-a', 'objects',
443
+ 'foo-bar'))
444
+
445
+ def testFlattenToDict(self):
446
+ class TestClass(command_base.GoogleComputeCommand):
447
+ fields = (('name', 'id'),
448
+ ('simple', 'path.to.object'),
449
+ ('multiple', 'more.elements'),
450
+ ('multiple', 'even_more.elements'),
451
+ ('repeated', 'things'),
452
+ ('long', 'l'),
453
+ ('does not exist', 'dne'),
454
+ ('partial match', 'path.to.nowhere'),
455
+ )
456
+
457
+ data = {'id': ('https://www.googleapis.com/compute/v1beta1/' +
458
+ 'projects/test/object/foo'),
459
+ 'path': {'to': {'object': 'bar'}},
460
+ 'more': [{'elements': 'a'}, {'elements': 'b'}],
461
+ 'even_more': [{'elements': 800}, {'elements': 800}],
462
+ 'things': [1, 2, 3],
463
+ 'l': 'n' * 80}
464
+ expected_result = ['foo', 'bar', 'a,b', '800,800', '1,2,3',
465
+ '%s..%s' % ('n' * 31, 'n' * 31), '', '']
466
+ flag_values = copy.deepcopy(FLAGS)
467
+ flag_values.project = 'test'
468
+ test_class = TestClass('foo', flag_values)
469
+ test_class.SetFlags(flag_values)
470
+ flattened = test_class._FlattenObjectToList(data, test_class.fields)
471
+ self.assertEquals(flattened, expected_result)
472
+
473
+ def testFlattenToDictWithMultipleTargets(self):
474
+ class TestClass(command_base.GoogleComputeCommand):
475
+ fields = (('name', ('name', 'id')),
476
+ ('simple', ('path.to.object', 'foo')),
477
+ ('multiple', 'more.elements'),
478
+ ('multiple', 'even_more.elements'),
479
+ ('repeated', 'things'),
480
+ ('long', ('l', 'longer')),
481
+ ('does not exist', 'dne'),
482
+ ('partial match', 'path.to.nowhere'),
483
+ )
484
+
485
+ data = {'name': ('https://www.googleapis.com/compute/v1beta1/' +
486
+ 'projects/test/object/foo'),
487
+ 'path': {'to': {'object': 'bar'}},
488
+ 'more': [{'elements': 'a'}, {'elements': 'b'}],
489
+ 'even_more': [{'elements': 800}, {'elements': 800}],
490
+ 'things': [1, 2, 3],
491
+ 'longer': 'n' * 80}
492
+ expected_result = ['foo', 'bar', 'a,b', '800,800', '1,2,3',
493
+ '%s..%s' % ('n' * 31, 'n' * 31), '', '']
494
+ flag_values = copy.deepcopy(FLAGS)
495
+ flag_values.project = 'test'
496
+ test_class = TestClass('foo', flag_values)
497
+ test_class.SetFlags(flag_values)
498
+ flattened = test_class._FlattenObjectToList(data, test_class.fields)
499
+ self.assertEquals(flattened, expected_result)
500
+
501
+ def testPositionArgumentParsing(self):
502
+ class MockCommand(command_base.GoogleComputeCommand):
503
+
504
+ def __init__(self, name, flag_values):
505
+ super(MockCommand, self).__init__(name, flag_values)
506
+ flags.DEFINE_string('mockflag',
507
+ 'wrong_mock_flag',
508
+ 'Mock Flag',
509
+ flag_values=flag_values)
510
+
511
+ def Handle(self, arg1, arg2, arg3):
512
+ pass
513
+
514
+ flag_values = copy.deepcopy(FLAGS)
515
+ command = MockCommand('mock_command', flag_values)
516
+
517
+ expected_arg1 = 'foo'
518
+ expected_arg2 = 'bar'
519
+ expected_arg3 = 'baz'
520
+ expected_flagvalue = 'wow'
521
+
522
+ command_line = ['mock_command', expected_arg1, expected_arg2,
523
+ expected_arg3, '--mockflag=' + expected_flagvalue]
524
+
525
+ # Verify the positional argument parser correctly identifies the parameters
526
+ # and flags.
527
+ result = command._ParseArgumentsAndFlags(flag_values, command_line)
528
+
529
+ self.assertEqual(result[0], expected_arg1)
530
+ self.assertEqual(result[1], expected_arg2)
531
+ self.assertEqual(result[2], expected_arg3)
532
+ self.assertEqual(flag_values.mockflag, expected_flagvalue)
533
+
534
+ def testErroneousKeyWordArgumentParsing(self):
535
+ class MockCommand(command_base.GoogleComputeCommand):
536
+
537
+ def __init__(self, name, flag_values):
538
+ super(MockCommand, self).__init__(name, flag_values)
539
+ flags.DEFINE_integer('mockflag',
540
+ 10,
541
+ 'Mock Flag',
542
+ flag_values=flag_values,
543
+ lower_bound=0)
544
+
545
+ def Handle(self, arg1, arg2, arg3):
546
+ pass
547
+
548
+ flag_values = copy.deepcopy(FLAGS)
549
+ command = MockCommand('mock_command', flag_values)
550
+
551
+ # Ensures that a type mistmatch for a keyword argument causes a
552
+ # CommandError to be raised.
553
+ bad_values = [-100, -2, 0.2, .30, 100.1]
554
+ for val in bad_values:
555
+ command_line = ['mock_command', '--mockflag=%s' % val]
556
+ self.assertRaises(command_base.CommandError,
557
+ command._ParseArgumentsAndFlags,
558
+ flag_values, command_line)
559
+
560
+ # Ensures that passing a nonexistent keyword argument also causes
561
+ # a CommandError to be raised.
562
+ command_line = ['mock_command', '--nonexistent_flag=boo!']
563
+ self.assertRaises(command_base.CommandError,
564
+ command._ParseArgumentsAndFlags,
565
+ flag_values, command_line)
566
+
567
+ def testSafetyPromptYes(self):
568
+ flag_values = copy.deepcopy(FLAGS)
569
+ command_line = ['mock_command']
570
+
571
+ command = CommandBaseTest.MockSafetyCommand('mock_command', flag_values)
572
+ args = command._ParseArgumentsAndFlags(flag_values, command_line)
573
+ command.SetFlags(flag_values)
574
+
575
+ mock_output = mock_api.MockOutput()
576
+ mock_input = mock_api.MockInput('Y\n\r')
577
+
578
+ oldin = sys.stdin
579
+ sys.stdin = mock_input
580
+ oldout = sys.stdout
581
+ sys.stdout = mock_output
582
+
583
+ result = command._HandleSafetyPrompt(args)
584
+
585
+ self.assertEqual(mock_output.GetCapturedText(),
586
+ 'Take scary action? [y/N]\n>>> ')
587
+ self.assertEqual(result, True)
588
+
589
+ sys.stdin = oldin
590
+ sys.stdout = oldout
591
+
592
+ def testSafetyPromptWithArgsYes(self):
593
+ flag_values = copy.deepcopy(FLAGS)
594
+ command_line = ['mock_cmd', 'arg1', 'arg2']
595
+
596
+ command = CommandBaseTest.MockSafetyCommandWithArgs('mock_cmd', flag_values)
597
+ args = command._ParseArgumentsAndFlags(flag_values, command_line)
598
+ command.SetFlags(flag_values)
599
+
600
+ mock_output = CommandBaseTest.CaptureOutput()
601
+ mock_input = CommandBaseTest.MockInput('Y\n\r')
602
+
603
+ oldin = sys.stdin
604
+ sys.stdin = mock_input
605
+ oldout = sys.stdout
606
+ sys.stdout = mock_output
607
+
608
+ result = command._HandleSafetyPrompt(args)
609
+
610
+ self.assertEqual(mock_output.GetCapturedText(),
611
+ 'Act on arg1, arg2? [y/N]\n>>> ')
612
+ self.assertEqual(result, True)
613
+
614
+ sys.stdin = oldin
615
+ sys.stdout = oldout
616
+
617
+ def testSafetyPromptMissingArgs(self):
618
+ flag_values = copy.deepcopy(FLAGS)
619
+ command_line = ['mock_cmd', 'arg1']
620
+
621
+ command = CommandBaseTest.MockSafetyCommandWithArgs('mock_cmd', flag_values)
622
+
623
+ command_base.sys.exit = CommandBaseTest.FakeExit()
624
+ sys.stderr = CommandBaseTest.CaptureOutput()
625
+
626
+ gcutil_logging.SetupLogging()
627
+ self.assertRaises(command_base.CommandError,
628
+ command._ParseArgumentsAndFlags,
629
+ flag_values, command_line)
630
+
631
+ def testSafetyPromptExtraArgs(self):
632
+ flag_values = copy.deepcopy(FLAGS)
633
+ command_line = ['mock_cmd', 'arg1', 'arg2', 'arg3']
634
+
635
+ command = CommandBaseTest.MockSafetyCommandWithArgs('mock_cmd', flag_values)
636
+
637
+ command_base.sys.exit = CommandBaseTest.FakeExit()
638
+ sys.stderr = CommandBaseTest.CaptureOutput()
639
+
640
+ gcutil_logging.SetupLogging()
641
+ self.assertRaises(command_base.CommandError,
642
+ command._ParseArgumentsAndFlags,
643
+ flag_values, command_line)
644
+
645
+ def testSafetyPromptNo(self):
646
+ flag_values = copy.deepcopy(FLAGS)
647
+ command_line = ['mock_command']
648
+
649
+ command = CommandBaseTest.MockSafetyCommand('mock_command', flag_values)
650
+ args = command._ParseArgumentsAndFlags(flag_values, command_line)
651
+ command.SetFlags(flag_values)
652
+
653
+ mock_output = mock_api.MockOutput()
654
+ mock_input = mock_api.MockInput('garbage\n\r')
655
+
656
+ oldin = sys.stdin
657
+ sys.stdin = mock_input
658
+ oldout = sys.stdout
659
+ sys.stdout = mock_output
660
+
661
+ result = command._HandleSafetyPrompt(args)
662
+
663
+ self.assertEqual(mock_output.GetCapturedText(),
664
+ 'Take scary action? [y/N]\n>>> ')
665
+ self.assertEqual(result, False)
666
+
667
+ sys.stdin = oldin
668
+ sys.stdout = oldout
669
+
670
+ def testSafetyPromptForce(self):
671
+ flag_values = copy.deepcopy(FLAGS)
672
+ command_line = ['mock_command', '--force']
673
+
674
+ command = CommandBaseTest.MockSafetyCommand('mock_command', flag_values)
675
+ args = command._ParseArgumentsAndFlags(flag_values, command_line)
676
+ command.SetFlags(flag_values)
677
+
678
+ mock_output = mock_api.MockOutput()
679
+
680
+ oldout = sys.stdout
681
+ sys.stdout = mock_output
682
+
683
+ result = command._HandleSafetyPrompt(args)
684
+
685
+ sys.stdout = oldout
686
+
687
+ self.assertEqual(result, True)
688
+ self.assertEqual(mock_output.GetCapturedText(), '')
689
+
690
+ def testPromptForEntryWithZeroItems(self):
691
+
692
+ class MockCollectionApi(object):
693
+
694
+ def list(self, project=None, maxResults=None, filter=None, pageToken=None):
695
+ return mock_api.MockRequest(
696
+ {'kind': 'compute#collectionList',
697
+ 'id': 'projects/p/collection',
698
+ 'selfLink':
699
+ 'https://www.googleapis.com/compute/v1/projects/p/collection'
700
+ })
701
+
702
+ flag_values = copy.deepcopy(FLAGS)
703
+ flag_values.project = 'p'
704
+
705
+ command = command_base.GoogleComputeCommand('mock_command', flag_values)
706
+ command.SetFlags(flag_values)
707
+ self.assertEqual(
708
+ command._PromptForEntry(MockCollectionApi(), 'collection'),
709
+ None)
710
+
711
+ def testPromptForEntryWithOneItem(self):
712
+
713
+ class MockCollectionApi(object):
714
+
715
+ def list(self, project=None, maxResults=None, filter=None, pageToken=None):
716
+ return mock_api.MockRequest(
717
+ {'kind': 'compute#collectionList',
718
+ 'id': 'projects/p/collection',
719
+ 'selfLink':
720
+ 'https://www.googleapis.com/compute/v1/projects/p/collection',
721
+ 'items': [{'name': 'item-1'}]
722
+ })
723
+
724
+ flag_values = copy.deepcopy(FLAGS)
725
+ flag_values.project = 'p'
726
+
727
+ command = command_base.GoogleComputeCommand('mock_command', flag_values)
728
+ command.SetFlags(flag_values)
729
+
730
+ # Tests _PromptForEntry with auto selecting on.
731
+ self.assertEqual(command._PromptForEntry(MockCollectionApi(), 'collection',
732
+ auto_select=True),
733
+ {'name': 'item-1'})
734
+
735
+ # Tests _PromptForEntry with auto selecting off.
736
+ mock_output = CommandBaseTest.CaptureOutput()
737
+ mock_input = CommandBaseTest.MockInput('1\n')
738
+
739
+ oldin = sys.stdin
740
+ sys.stdin = mock_input
741
+ oldout = sys.stdout
742
+ sys.stdout = mock_output
743
+
744
+ result = command._PromptForEntry(MockCollectionApi(), 'collection',
745
+ auto_select=False)
746
+
747
+ self.assertEqual(mock_output.GetCapturedText(),
748
+ '1: item-1\n>>> ')
749
+ self.assertEqual(result, {'name': 'item-1'})
750
+
751
+ sys.stdin = oldin
752
+ sys.stdout = oldout
753
+
754
+ def testPromptForEntryWithManyItems(self):
755
+
756
+ class MockCollectionApi(object):
757
+
758
+ def list(self, project=None, maxResults=None, filter=None, pageToken=None):
759
+ return mock_api.MockRequest(
760
+ {'kind': 'compute#collectionList',
761
+ 'id': 'projects/p/collection',
762
+ 'selfLink':
763
+ 'https://www.googleapis.com/compute/v1/projects/p/collection',
764
+ 'items': [{'name': 'item-1'},
765
+ {'name': 'item-2'},
766
+ {'name': 'item-3'},
767
+ {'name': 'item-4'}]})
768
+
769
+ flag_values = copy.deepcopy(FLAGS)
770
+ flag_values.project = 'p'
771
+
772
+ command = command_base.GoogleComputeCommand('mock_command', flag_values)
773
+ command.SetFlags(flag_values)
774
+
775
+ mock_output = CommandBaseTest.CaptureOutput()
776
+ mock_input = CommandBaseTest.MockInput('3\n')
777
+
778
+ oldin = sys.stdin
779
+ sys.stdin = mock_input
780
+ oldout = sys.stdout
781
+ sys.stdout = mock_output
782
+
783
+ result = command._PromptForEntry(MockCollectionApi(), 'collection',
784
+ auto_select=False)
785
+
786
+ self.assertEqual(
787
+ mock_output.GetCapturedText(),
788
+ '\n'.join(('1: item-1', '2: item-2', '3: item-3', '4: item-4', '>>> ')))
789
+ self.assertEqual(result, {'name': 'item-3'})
790
+
791
+ sys.stdin = oldin
792
+ sys.stdout = oldout
793
+
794
+ def testPromptForEntryWithManyItemsAndAdditionalKeyFunc(self):
795
+
796
+ class MockCollectionApi(object):
797
+
798
+ def list(self, project=None, maxResults=None, filter=None,
799
+ pageToken=None):
800
+ return mock_api.MockRequest(
801
+ {'kind': 'compute#machineTypeList',
802
+ 'id': 'projects/p/machineTypes',
803
+ 'selfLink': ('https://www.googleapis.com/compute/v1/projects/p/'
804
+ 'machineTypes'),
805
+ 'items': [{'name': 'n1-highcpu-4-d'},
806
+ {'name': 'n1-standard-2'},
807
+ {'name': 'n1-standard-1-d'},
808
+ {'name': 'n1-standard-8-d'},
809
+ {'name': 'n1-highcpu-8-d'},
810
+ {'name': 'n1-standard-2-d'},
811
+ {'name': 'n1-standard-1'},
812
+ {'name': 'n1-standard-4'},
813
+ {'name': 'n1-highmem-4'},
814
+ {'name': 'n1-highcpu-4'},
815
+ {'name': 'n1-highcpu-2'},
816
+ {'name': 'n1-standard-4-d'},
817
+ {'name': 'n1-standard-8'},
818
+ {'name': 'n1-highmem-2'},
819
+ {'name': 'n1-highmem-2-d'},
820
+ {'name': 'n1-highcpu-2-d'},
821
+ {'name': 'n1-highmem-8'},
822
+ {'name': 'n1-highcpu-8'},
823
+ {'name': 'n1-highmem-8-d'},
824
+ {'name': 'n1-highmem-4-d'}]})
825
+
826
+ flag_values = copy.deepcopy(FLAGS)
827
+ flag_values.project = 'p'
828
+
829
+ command = command_base.GoogleComputeCommand('mock_command', flag_values)
830
+ command.SetFlags(flag_values)
831
+
832
+ mock_output = CommandBaseTest.CaptureOutput()
833
+ mock_input = CommandBaseTest.MockInput('3\n')
834
+
835
+ oldin = sys.stdin
836
+ sys.stdin = mock_input
837
+ oldout = sys.stdout
838
+ sys.stdout = mock_output
839
+
840
+ result = command._PromptForEntry(
841
+ MockCollectionApi(), 'machine type', auto_select=False,
842
+ additional_key_func=command._GetMachineTypeSecondarySortScore)
843
+
844
+ self.assertEqual(
845
+ mock_output.GetCapturedText(),
846
+ '\n'.join((
847
+ '1: n1-standard-1',
848
+ '2: n1-standard-1-d',
849
+ '3: n1-standard-2',
850
+ '4: n1-standard-2-d',
851
+ '5: n1-standard-4',
852
+ '6: n1-standard-4-d',
853
+ '7: n1-standard-8',
854
+ '8: n1-standard-8-d',
855
+ '9: n1-highcpu-2',
856
+ '10: n1-highcpu-2-d',
857
+ '11: n1-highcpu-4',
858
+ '12: n1-highcpu-4-d',
859
+ '13: n1-highcpu-8',
860
+ '14: n1-highcpu-8-d',
861
+ '15: n1-highmem-2',
862
+ '16: n1-highmem-2-d',
863
+ '17: n1-highmem-4',
864
+ '18: n1-highmem-4-d',
865
+ '19: n1-highmem-8',
866
+ '20: n1-highmem-8-d',
867
+ '>>> ')))
868
+ self.assertEqual(result, {'name': 'n1-standard-2'})
869
+
870
+ sys.stdin = oldin
871
+ sys.stdout = oldout
872
+
873
+ def testPromptForEntryWithDeprecatedItems(self):
874
+
875
+ class MockCollectionApi(object):
876
+
877
+ def list(self, project=None, maxResults=None, filter=None, pageToken=None):
878
+ return mock_api.MockRequest(
879
+ {'kind': 'compute#collectionList',
880
+ 'id': 'projects/p/collection',
881
+ 'selfLink':
882
+ 'https://www.googleapis.com/compute/v1/projects/p/collection',
883
+ 'items': [{'name': 'item-1',
884
+ 'deprecated':
885
+ {'state': 'DEPRECATED'}},
886
+ {'name': 'item-2'},
887
+ {'name': 'item-3',
888
+ 'deprecated':
889
+ {'state': 'OBSOLETE'}},
890
+ {'name': 'item-4'},
891
+ {'name': 'item-5',
892
+ 'deprecated':
893
+ {'state': 'DEPRECATED'}},
894
+ {'name': 'item-6',
895
+ 'deprecated':
896
+ {'state': 'DELETED'}}]})
897
+
898
+ flag_values = copy.deepcopy(FLAGS)
899
+ flag_values.project = 'p'
900
+
901
+ command = command_base.GoogleComputeCommand('mock_command', flag_values)
902
+ command.SetFlags(flag_values)
903
+
904
+ mock_output = CommandBaseTest.CaptureOutput()
905
+ mock_input = CommandBaseTest.MockInput('3\n')
906
+
907
+ oldin = sys.stdin
908
+ sys.stdin = mock_input
909
+ oldout = sys.stdout
910
+ sys.stdout = mock_output
911
+
912
+ result = command._PromptForEntry(MockCollectionApi(), 'collection',
913
+ auto_select=False)
914
+
915
+ self.assertEqual(
916
+ mock_output.GetCapturedText(),
917
+ '\n'.join(('1: item-2', '2: item-4', '3: item-1 (DEPRECATED)',
918
+ '4: item-5 (DEPRECATED)', '>>> ')))
919
+ self.assertEqual(result, {'name': 'item-1', 'deprecated':
920
+ {'state': 'DEPRECATED'}})
921
+ sys.stdin = oldin
922
+ sys.stdout = oldout
923
+
924
+ def testPromptForChoicesWithOneDeprecatedItem(self):
925
+ class MockCollectionApi(object):
926
+
927
+ def list(self, project=None, maxResults=None, filter=None, pageToken=None):
928
+ return mock_api.MockRequest(
929
+ {'kind': 'compute#collectionList',
930
+ 'id': 'projects/p/collection',
931
+ 'selfLink':
932
+ 'https://www.googleapis.com/compute/v1/projects/p/collection',
933
+ 'items': [{'name': 'item-1',
934
+ 'deprecated':
935
+ {'state': 'DEPRECATED'}}]})
936
+
937
+ flag_values = copy.deepcopy(FLAGS)
938
+ flag_values.project = 'p'
939
+
940
+ command = command_base.GoogleComputeCommand('mock_command', flag_values)
941
+ command.SetFlags(flag_values)
942
+
943
+ mock_output = CommandBaseTest.CaptureOutput()
944
+
945
+ oldout = sys.stdout
946
+ sys.stdout = mock_output
947
+
948
+ result = command._PromptForEntry(MockCollectionApi(), 'collection')
949
+
950
+ self.assertEqual(
951
+ mock_output.GetCapturedText(),
952
+ 'Selecting the only available collection: item-1\n')
953
+ self.assertEqual(result, {'name': 'item-1', 'deprecated':
954
+ {'state': 'DEPRECATED'}})
955
+ sys.stdout = oldout
956
+
957
+ def testDetailOutput(self):
958
+ flag_values = copy.deepcopy(FLAGS)
959
+ flag_values.project = 'user'
960
+
961
+ command = CommandBaseTest.MockDetailCommand('mock_command', flag_values)
962
+ expected_output = (u'+-------------+-------------+\n'
963
+ '| property | value |\n'
964
+ '+-------------+-------------+\n'
965
+ '| name | my-object-c |\n'
966
+ '| id | 123 |\n'
967
+ '| description | Object C |\n'
968
+ '| additional | foo |\n'
969
+ '+-------------+-------------+\n')
970
+ mock_output = mock_api.MockOutput()
971
+
972
+ oldout = sys.stdout
973
+ sys.stdout = mock_output
974
+
975
+ command.SetFlags(flag_values)
976
+ result = command.Handle()
977
+ command.PrintResult(result)
978
+
979
+ sys.stdout = oldout
980
+
981
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
982
+
983
+ def testEmptyList(self):
984
+ flag_values = copy.deepcopy(FLAGS)
985
+ flag_values.project = 'user'
986
+
987
+ class ListEmptyMockCommand(CommandBaseTest.ListMockCommand):
988
+ def __init__(self, name, flag_values):
989
+ super(ListEmptyMockCommand, self).__init__(name, flag_values)
990
+
991
+ def Handle(self):
992
+ return {'kind': 'cloud#objectsList'}
993
+
994
+ command = ListEmptyMockCommand('empty_list', flag_values)
995
+ expected_output = (u'+------+----+-------------+\n'
996
+ '| name | id | description |\n'
997
+ '+------+----+-------------+\n'
998
+ '+------+----+-------------+\n')
999
+ mock_output = mock_api.MockOutput()
1000
+
1001
+ oldout = sys.stdout
1002
+ sys.stdout = mock_output
1003
+
1004
+ command.SetFlags(flag_values)
1005
+ result = command.Handle()
1006
+ command.PrintResult(result)
1007
+
1008
+ sys.stdout = oldout
1009
+
1010
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
1011
+
1012
+ def testSortingNone(self):
1013
+ flag_values = copy.deepcopy(FLAGS)
1014
+ flag_values.project = 'user'
1015
+
1016
+ command = CommandBaseTest.ListMockCommandBase('mock_command', flag_values)
1017
+ expected_output = (u'+-------------+-----+-------------+\n'
1018
+ '| name | id | description |\n'
1019
+ '+-------------+-----+-------------+\n'
1020
+ '| my-object-c | 123 | Object C |\n'
1021
+ '| my-object-a | 789 | Object A |\n'
1022
+ '| my-object-b | 456 | Object B |\n'
1023
+ '| my-object-d | 999 | Object D |\n'
1024
+ '+-------------+-----+-------------+\n')
1025
+ mock_output = mock_api.MockOutput()
1026
+
1027
+ oldout = sys.stdout
1028
+ sys.stdout = mock_output
1029
+
1030
+ command.SetFlags(flag_values)
1031
+ result = command.Handle()
1032
+ command.PrintResult(result)
1033
+
1034
+ sys.stdout = oldout
1035
+
1036
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
1037
+
1038
+ def testSortingDefault(self):
1039
+ flag_values = copy.deepcopy(FLAGS)
1040
+ flag_values.project = 'user'
1041
+
1042
+ command = CommandBaseTest.ListMockCommand('mock_command', flag_values)
1043
+ mock_output = mock_api.MockOutput()
1044
+ expected_output = (u'+-------------+-----+-------------+\n'
1045
+ '| name | id | description |\n'
1046
+ '+-------------+-----+-------------+\n'
1047
+ '| my-object-a | 789 | Object A |\n'
1048
+ '| my-object-b | 456 | Object B |\n'
1049
+ '| my-object-c | 123 | Object C |\n'
1050
+ '| my-object-d | 999 | Object D |\n'
1051
+ '+-------------+-----+-------------+\n')
1052
+
1053
+ oldout = sys.stdout
1054
+ sys.stdout = mock_output
1055
+
1056
+ command.SetFlags(flag_values)
1057
+ result = command.Handle()
1058
+ command.PrintResult(result)
1059
+
1060
+ sys.stdout = oldout
1061
+
1062
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
1063
+
1064
+ def testSortingSpecifiedInAscendingOrder(self):
1065
+ flag_values = copy.deepcopy(FLAGS)
1066
+ flag_values.project = 'user'
1067
+
1068
+ command = CommandBaseTest.ListMockCommand('mock_command', flag_values)
1069
+ mock_output = mock_api.MockOutput()
1070
+
1071
+ flag_values.sort_by = 'id'
1072
+
1073
+ expected_output = (u'+-------------+-----+-------------+\n'
1074
+ '| name | id | description |\n'
1075
+ '+-------------+-----+-------------+\n'
1076
+ '| my-object-c | 123 | Object C |\n'
1077
+ '| my-object-b | 456 | Object B |\n'
1078
+ '| my-object-a | 789 | Object A |\n'
1079
+ '| my-object-d | 999 | Object D |\n'
1080
+ '+-------------+-----+-------------+\n')
1081
+
1082
+ oldout = sys.stdout
1083
+ sys.stdout = mock_output
1084
+
1085
+ command.SetFlags(flag_values)
1086
+ result = command.Handle()
1087
+ command.PrintResult(result)
1088
+
1089
+ sys.stdout = oldout
1090
+
1091
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
1092
+
1093
+ def testSortingSpecifiedInDescendingOrder(self):
1094
+ flag_values = copy.deepcopy(FLAGS)
1095
+ flag_values.project = 'user'
1096
+
1097
+ command = CommandBaseTest.ListMockCommand('mock_command', flag_values)
1098
+ mock_output = mock_api.MockOutput()
1099
+
1100
+ flag_values.sort_by = '-id'
1101
+
1102
+ expected_output = (u'+-------------+-----+-------------+\n'
1103
+ '| name | id | description |\n'
1104
+ '+-------------+-----+-------------+\n'
1105
+ '| my-object-d | 999 | Object D |\n'
1106
+ '| my-object-a | 789 | Object A |\n'
1107
+ '| my-object-b | 456 | Object B |\n'
1108
+ '| my-object-c | 123 | Object C |\n'
1109
+ '+-------------+-----+-------------+\n')
1110
+
1111
+ oldout = sys.stdout
1112
+ sys.stdout = mock_output
1113
+
1114
+ command.SetFlags(flag_values)
1115
+ result = command.Handle()
1116
+ command.PrintResult(result)
1117
+
1118
+ sys.stdout = oldout
1119
+
1120
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
1121
+
1122
+ def testGracefulHandlingOfInvalidDefaultSortField(self):
1123
+
1124
+ class ListMockCommandWithBadDefaultSortField(
1125
+ CommandBaseTest.ListMockCommandBase):
1126
+
1127
+ default_sort_field = 'bad-field-name'
1128
+
1129
+ def __init__(self, name, flag_values):
1130
+ super(ListMockCommandWithBadDefaultSortField, self).__init__(
1131
+ name, flag_values)
1132
+
1133
+ flag_values = copy.deepcopy(FLAGS)
1134
+ flag_values.project = 'user'
1135
+
1136
+ command = ListMockCommandWithBadDefaultSortField(
1137
+ 'mock_command', flag_values)
1138
+
1139
+ # The output is expected to remain unsorted if the default sort
1140
+ # field is invalid.
1141
+ expected_output = (u'+-------------+-----+-------------+\n'
1142
+ '| name | id | description |\n'
1143
+ '+-------------+-----+-------------+\n'
1144
+ '| my-object-c | 123 | Object C |\n'
1145
+ '| my-object-a | 789 | Object A |\n'
1146
+ '| my-object-b | 456 | Object B |\n'
1147
+ '| my-object-d | 999 | Object D |\n'
1148
+ '+-------------+-----+-------------+\n')
1149
+ mock_output = mock_api.MockOutput()
1150
+
1151
+ oldout = sys.stdout
1152
+ sys.stdout = mock_output
1153
+
1154
+ command.SetFlags(flag_values)
1155
+ result = command.Handle()
1156
+ command.PrintResult(result)
1157
+
1158
+ sys.stdout = oldout
1159
+
1160
+ self.assertEqual(mock_output.GetCapturedText(), expected_output)
1161
+
1162
+ def testVersionComparison(self):
1163
+ class MockCommand(CommandBaseTest.ListMockCommand):
1164
+ def __init__(self, name, flag_values):
1165
+ super(MockCommand, self).__init__(name, flag_values)
1166
+
1167
+ flag_values = copy.deepcopy(FLAGS)
1168
+
1169
+ command = MockCommand('mock_command', flag_values)
1170
+ command.supported_versions = ['v1beta2', 'v1beta3', 'v1beta4',
1171
+ 'v1beta5', 'v1beta6']
1172
+
1173
+ flag_values.service_version = 'v1beta4'
1174
+ command.SetFlags(flag_values)
1175
+ self.assertFalse(command._IsUsingAtLeastApiVersion('v1beta6'))
1176
+ self.assertFalse(command._IsUsingAtLeastApiVersion('v1beta5'))
1177
+ self.assertTrue(command._IsUsingAtLeastApiVersion('v1beta4'))
1178
+ self.assertTrue(command._IsUsingAtLeastApiVersion('v1beta2'))
1179
+
1180
+ flag_values.service_version = 'v1beta6'
1181
+ command.SetFlags(flag_values)
1182
+ self.assertTrue(command._IsUsingAtLeastApiVersion('v1beta6'))
1183
+ self.assertTrue(command._IsUsingAtLeastApiVersion('v1beta5'))
1184
+ self.assertTrue(command._IsUsingAtLeastApiVersion('v1beta4'))
1185
+ self.assertTrue(command._IsUsingAtLeastApiVersion('v1beta2'))
1186
+
1187
+ def testTracing(self):
1188
+ class MockComputeApi(object):
1189
+ def __init__(self, trace_calls):
1190
+ self._trace_calls = trace_calls
1191
+
1192
+ def Disks(self):
1193
+ class MockDisksApi(object):
1194
+ def __init__(self, trace_calls):
1195
+ self._trace_calls = trace_calls
1196
+
1197
+ def Insert(self, trace=None):
1198
+ if trace:
1199
+ self._trace_calls.append(trace)
1200
+
1201
+ return MockDisksApi(self._trace_calls)
1202
+
1203
+ # Expect no tracing if flag is not set.
1204
+ trace_calls = []
1205
+ compute = command_base.GoogleComputeCommand.WrapApiIfNeeded(
1206
+ MockComputeApi(trace_calls))
1207
+ compute.Disks().Insert()
1208
+ self.assertEqual(0, len(trace_calls))
1209
+
1210
+ # Expect tracing if trace_token flag is set.
1211
+ trace_calls = []
1212
+ FLAGS.trace_token = 'THE_TOKEN'
1213
+ compute = command_base.GoogleComputeCommand.WrapApiIfNeeded(
1214
+ MockComputeApi(trace_calls))
1215
+ compute.Disks().Insert()
1216
+ self.assertEqual(1, len(trace_calls))
1217
+ self.assertEqual('token:THE_TOKEN', trace_calls[0])
1218
+ FLAGS.trace_token = ''
1219
+
1220
+
1221
+ def testWaitForOperation(self):
1222
+ complete_name = 'operation-complete'
1223
+ running_name = 'operation-running'
1224
+ pending_name = 'operation-pending'
1225
+ stuck_name = 'operation-stuck'
1226
+
1227
+ base_operation = {'kind': 'cloud#operation',
1228
+ 'targetLink': ('https://www.googleapis.com/compute/'
1229
+ 'v1beta100/projects/p/instances/i1'),
1230
+ 'operationType': 'insert'}
1231
+
1232
+ completed_operation = dict(base_operation)
1233
+ completed_operation.update({'name': complete_name,
1234
+ 'status': 'DONE'})
1235
+ running_operation = dict(base_operation)
1236
+ running_operation.update({'name': running_name,
1237
+ 'status': 'RUNNING'})
1238
+ pending_operation = dict(base_operation)
1239
+ pending_operation.update({'name': pending_name,
1240
+ 'status': 'PENDING'})
1241
+ stuck_operation = dict(base_operation)
1242
+ stuck_operation.update({'name': stuck_name,
1243
+ 'status': 'PENDING'})
1244
+
1245
+ next_operation = {complete_name: completed_operation,
1246
+ running_name: completed_operation,
1247
+ pending_name: running_operation,
1248
+ stuck_name: stuck_operation}
1249
+
1250
+
1251
+ class MockHttpResponse(object):
1252
+ def __init__(self, status, reason):
1253
+ self.status = status
1254
+ self.reason = reason
1255
+
1256
+ class MockHttp(object):
1257
+ def request(self_, url, method='GET', body=None, headers=None):
1258
+ response = MockHttpResponse(200, 'OK')
1259
+ data = '{ "kind": "compute#instance", "name": "i1" }'
1260
+ return response, data
1261
+
1262
+ class MockCommand(command_base.GoogleComputeCommand):
1263
+ def __init__(self, name, flag_values):
1264
+ super(MockCommand, self).__init__(name, flag_values)
1265
+
1266
+ def SetApi(self, api):
1267
+ pass
1268
+
1269
+ def Handle(self):
1270
+ pass
1271
+
1272
+ def CreateHttp(self):
1273
+ return MockHttp()
1274
+
1275
+ class MockTimer(object):
1276
+ def __init__(self):
1277
+ self._current_time = 0
1278
+
1279
+ def time(self):
1280
+ return self._current_time
1281
+
1282
+ def sleep(self, time_to_sleep):
1283
+ self._current_time += time_to_sleep
1284
+ return self._current_time
1285
+
1286
+ class LocalMockOperationsApi(object):
1287
+ def __init__(self):
1288
+ self._get_call_count = 0
1289
+
1290
+ def GetCallCount(self):
1291
+ return self._get_call_count
1292
+
1293
+ def get(self, project='unused project', operation='operation'):
1294
+ unused_project = project
1295
+ self._get_call_count += 1
1296
+ return mock_api.MockRequest(next_operation[operation])
1297
+
1298
+ flag_values = copy.deepcopy(FLAGS)
1299
+ flag_values.sleep_between_polls = 1
1300
+ flag_values.max_wait_time = 30
1301
+ flag_values.service_version = 'v1beta13'
1302
+ flag_values.synchronous_mode = False
1303
+ flag_values.project = 'test'
1304
+
1305
+ # Ensure a synchronous result returns immediately.
1306
+ timer = MockTimer()
1307
+ command = MockCommand('mock_command', flag_values)
1308
+ command.SetFlags(flag_values)
1309
+ command.SetApi(mock_api.MockApi())
1310
+ command._global_operations_api = LocalMockOperationsApi()
1311
+ diskResult = {'kind': 'cloud#disk'}
1312
+ result = command.WaitForOperation(flag_values, timer, diskResult)
1313
+ self.assertEqual(0, command._global_operations_api.GetCallCount())
1314
+
1315
+ # Ensure an asynchronous result loops until complete.
1316
+ timer = MockTimer()
1317
+ command = MockCommand('mock_command', flag_values)
1318
+ command.SetFlags(flag_values)
1319
+ command.SetApi(mock_api.MockApi())
1320
+ command._global_operations_api = LocalMockOperationsApi()
1321
+ result = command.WaitForOperation(flag_values, timer, pending_operation)
1322
+ self.assertEqual(2, command._global_operations_api.GetCallCount())
1323
+
1324
+ # Ensure an asynchronous result eventually times out
1325
+ timer = MockTimer()
1326
+ command = MockCommand('mock_command', flag_values)
1327
+ command.SetFlags(flag_values)
1328
+ command.SetApi(mock_api.MockApi())
1329
+ command._global_operations_api = LocalMockOperationsApi()
1330
+ result = command.WaitForOperation(flag_values, timer, stuck_operation)
1331
+ self.assertEqual(30, command._global_operations_api.GetCallCount())
1332
+ self.assertEqual(result['status'], 'PENDING')
1333
+
1334
+ def testBuildComputeApi(self):
1335
+ """Ensures that building of the API from the discovery succeeds."""
1336
+ flag_values = copy.deepcopy(FLAGS)
1337
+ command = command_base.GoogleComputeCommand('test_cmd', flag_values)
1338
+ command._BuildComputeApi(None)
1339
+
1340
+ def testGetZone(self):
1341
+ zones = {
1342
+ 'zone-a': {
1343
+ 'kind': 'compute#zone',
1344
+ 'id': '1',
1345
+ 'creationTimestamp': '2011-07-27T20:04:06.171',
1346
+ 'selfLink': (
1347
+ 'https://googleapis.com/compute/v1/projects/p/zones/zone-a'),
1348
+ 'name': 'zone-a',
1349
+ 'description': 'Zone zone/a',
1350
+ 'status': 'UP'},
1351
+ 'zone-b': {
1352
+ 'kind': 'compute#zone',
1353
+ 'id': '2',
1354
+ 'creationTimestamp': '2012-01-12T00:20:42.057',
1355
+ 'selfLink': (
1356
+ 'https://googleapis.com/compute/v1/projects/p/zones/zone-b'),
1357
+ 'name': 'zone-b',
1358
+ 'description': 'Zone zone/b',
1359
+ 'status': 'UP',
1360
+ 'maintenanceWindows': [
1361
+ {
1362
+ 'name': '2012-06-24-planned-outage',
1363
+ 'description': 'maintenance zone',
1364
+ 'beginTime': '2012-06-24T07:00:00.000',
1365
+ 'endTime': '2012-07-08T07:00:00.000'
1366
+ }
1367
+ ]
1368
+ }
1369
+ }
1370
+
1371
+ class MockCommand(command_base.GoogleComputeCommand):
1372
+ def __init__(self, name, flag_values):
1373
+ super(MockCommand, self).__init__(name, flag_values)
1374
+
1375
+ def SetApi(self, api):
1376
+ pass
1377
+
1378
+ def Handle(self):
1379
+ pass
1380
+
1381
+ class MockZonesApi(object):
1382
+
1383
+ def get(self, zone, **unused_kwargs):
1384
+ return mock_api.MockRequest(zones[zone])
1385
+
1386
+ def _PromptForZone():
1387
+ return zones['zone-a']
1388
+
1389
+ flag_values = copy.deepcopy(FLAGS)
1390
+ command = MockCommand('mock_command', flag_values)
1391
+ flag_values.project = 'p'
1392
+ command.SetFlags(flag_values)
1393
+ command._zones_api = MockZonesApi()
1394
+ command._PromptForZone = _PromptForZone
1395
+
1396
+ self.assertEqual(command._GetZone('zone-a'), 'zone-a')
1397
+ self.assertEqual(command._GetZone('zone-b'), 'zone-b')
1398
+ self.assertEqual(command._GetZone(None), 'zone-a')
1399
+
1400
+ def testGetNextMaintenanceStart(self):
1401
+ zone = {
1402
+ 'kind': 'compute#zone',
1403
+ 'name': 'zone',
1404
+ 'maintenanceWindows': [
1405
+ {
1406
+ 'name': 'january',
1407
+ 'beginTime': '2013-01-01T00:00:00.000',
1408
+ 'endTime': '2013-01-31T00:00:00.000'
1409
+ },
1410
+ {
1411
+ 'name': 'march',
1412
+ 'beginTime': '2013-03-01T00:00:00.000',
1413
+ 'endTime': '2013-03-31T00:00:00.000'
1414
+ },
1415
+ ]
1416
+ }
1417
+
1418
+ gnms = command_base.GoogleComputeCommand._GetNextMaintenanceStart
1419
+ start = gnms(zone, datetime.datetime(2012, 12, 1))
1420
+ self.assertEqual(start, datetime.datetime(2013, 1, 1))
1421
+ start = gnms(zone, datetime.datetime(2013, 2, 14))
1422
+ self.assertEqual(start, datetime.datetime(2013, 3, 1))
1423
+ start = gnms(zone, datetime.datetime(2013, 3, 15))
1424
+ self.assertEqual(start, datetime.datetime(2013, 3, 1))
1425
+
1426
+ def testGetZoneForResource(self):
1427
+ flag_values = copy.deepcopy(FLAGS)
1428
+ expected_project = 'google'
1429
+ flag_values.project = expected_project
1430
+ flag_values.service_version = 'v1beta13'
1431
+
1432
+ class MockCommand(command_base.GoogleComputeCommand):
1433
+
1434
+ resource_collection_name = 'foos'
1435
+
1436
+ def __init__(self, name, flag_values):
1437
+ super(MockCommand, self).__init__(name, flag_values)
1438
+ flags.DEFINE_string('zone',
1439
+ None,
1440
+ 'Zone name.',
1441
+ flag_values=flag_values)
1442
+ self.params = None
1443
+
1444
+ def RunWithFlagsAndPositionalArgs(self, flag_values, pos_arg_values):
1445
+ if self._flags != flag_values:
1446
+ raise RuntimeError('Flags mismatch')
1447
+ self.Handle(*pos_arg_values)
1448
+
1449
+ def Handle(self, param1, param2):
1450
+ self.params = (param1, param2)
1451
+ return None
1452
+
1453
+ class MockApi(object):
1454
+ list_response = None
1455
+
1456
+ def __init__(self):
1457
+ pass
1458
+
1459
+ def list(self, **kwargs):
1460
+ self.list_parameters = kwargs
1461
+ return self.list_response
1462
+
1463
+ class LocalMockZonesApi(object):
1464
+ def list(self, project='unused project', maxResults='unused',
1465
+ filter='unused'):
1466
+ return mock_api.MockRequest({'items': [{'name': 'zone1'}]})
1467
+
1468
+ command = MockCommand('mock_command', flag_values)
1469
+ command._zones_api = LocalMockZonesApi()
1470
+ api = MockApi()
1471
+ command.SetFlags(flag_values)
1472
+
1473
+ # Project-qualified name.
1474
+ self.assertEqual(
1475
+ command.GetZoneForResource(None, 'projects/foo/zones/bar'), 'bar')
1476
+
1477
+ # Special 'global' zone.
1478
+ flag_values.zone = 'global'
1479
+ command.SetFlags(flag_values)
1480
+ self.assertEqual(
1481
+ command.GetZoneForResource(None, command_base.GLOBAL_ZONE_NAME),
1482
+ None)
1483
+
1484
+ # Zone name explicitly set.
1485
+ flag_values.zone = 'explicitly-set-zone'
1486
+ command.SetFlags(flag_values)
1487
+ self.assertEqual(
1488
+ command.GetZoneForResource(None, 'some-resource'),
1489
+ 'explicitly-set-zone')
1490
+
1491
+
1492
+ def testGetUsageWithPositionalArgs(self):
1493
+
1494
+ class MockCommand(command_base.GoogleComputeCommand):
1495
+ positional_args = '<arg-1> ... <arg-n>'
1496
+
1497
+ flag_values = copy.deepcopy(FLAGS)
1498
+ command = MockCommand('mock_command', flag_values)
1499
+ self.assertTrue(command._GetUsage().endswith(
1500
+ ' [--global_flags] mock_command [--command_flags] <arg-1> ... <arg-n>'))
1501
+
1502
+ def testGetUsageWithNoPositionalArgs(self):
1503
+
1504
+ class MockCommand(command_base.GoogleComputeCommand):
1505
+ pass
1506
+
1507
+ flag_values = copy.deepcopy(FLAGS)
1508
+ command = MockCommand('mock_command', flag_values)
1509
+ self.assertTrue(command._GetUsage().endswith(
1510
+ ' [--global_flags] mock_command [--command_flags]'))
1511
+
1512
+
1513
+ def testGoogleComputeListCommandPerZone(self):
1514
+ flag_values = copy.deepcopy(FLAGS)
1515
+ expected_project = 'foo'
1516
+ flag_values.project = expected_project
1517
+ flag_values.service_version = 'v1beta14'
1518
+
1519
+ object_a = {'description': 'Object A',
1520
+ 'id': 'projects/user/zones/a/objects/my-object-a',
1521
+ 'kind': 'cloud#object'}
1522
+ object_b = {'description': 'Object B',
1523
+ 'id': 'projects/user/zones/b/objects/my-object-b',
1524
+ 'kind': 'cloud#object'}
1525
+ list_a = {'items': [object_a],
1526
+ 'kind': 'cloud#objectList'}
1527
+ list_b = {'items': [object_b],
1528
+ 'kind': 'cloud#objectList'}
1529
+ list_all = {'items': [object_a, object_b],
1530
+ 'kind': 'cloud#objectList'}
1531
+
1532
+ class LocalMockZonesApi(object):
1533
+ def list(self, project='unused project', maxResults='unused',
1534
+ filter='unused'):
1535
+ return mock_api.MockRequest({'items': [{'name': 'a'},
1536
+ {'name': 'b'}]})
1537
+
1538
+ class ZoneListMockCommand(CommandBaseTest.ListMockCommandBase):
1539
+ """A list mock command that represents a zone-scoped collection."""
1540
+ is_global_level_collection = False
1541
+ is_zone_level_collection = True
1542
+
1543
+ def __init__(self, name, flag_values):
1544
+ super(CommandBaseTest.ListMockCommandBase, self).__init__(name,
1545
+ flag_values)
1546
+ flags.DEFINE_string('zone',
1547
+ None,
1548
+ 'The zone to list.',
1549
+ flag_values=flag_values)
1550
+
1551
+ def ListZoneFunc(self):
1552
+ def Func(project=None, maxResults=None, filter=None, pageToken=None,
1553
+ zone=None):
1554
+ if zone == 'a':
1555
+ return mock_api.MockRequest(list_a)
1556
+ else:
1557
+ return mock_api.MockRequest(list_b)
1558
+
1559
+ return Func
1560
+
1561
+ command = ZoneListMockCommand('mock_command', flag_values)
1562
+ command._zones_api = LocalMockZonesApi()
1563
+
1564
+ # Test single zone
1565
+ flag_values.zone = 'a'
1566
+ command.SetFlags(flag_values)
1567
+ self.assertEqual(list_a, command.Handle())
1568
+
1569
+ # Test all zones
1570
+ flag_values.zone = None
1571
+ command.SetFlags(flag_values)
1572
+ self.assertEqual(list_all, command.Handle())
1573
+
1574
+ def testGoogleComputeListCommandZoneAndGlobal(self):
1575
+ flag_values = copy.deepcopy(FLAGS)
1576
+ expected_project = 'foo'
1577
+ flag_values.project = expected_project
1578
+ flag_values.service_version = 'v1beta14'
1579
+
1580
+ object_a = {'description': 'Object A',
1581
+ 'id': 'projects/user/zones/a/objects/my-object-a',
1582
+ 'kind': 'cloud#object'}
1583
+ object_b = {'description': 'Object B',
1584
+ 'id': 'projects/user/zones/b/objects/my-object-b',
1585
+ 'kind': 'cloud#object'}
1586
+ object_c = {'description': 'Object C',
1587
+ 'id': 'projects/user/objects/my-object-c',
1588
+ 'kind': 'cloud#object'}
1589
+ list_global = {'items': [object_c],
1590
+ 'kind': 'cloud#objectList'}
1591
+ list_a = {'items': [object_a],
1592
+ 'kind': 'cloud#objectList'}
1593
+ list_b = {'items': [object_b],
1594
+ 'kind': 'cloud#objectList'}
1595
+ list_all = {'items': [object_c, object_a, object_b],
1596
+ 'kind': 'cloud#objectList'}
1597
+
1598
+ class LocalMockZonesApi(object):
1599
+ def list(self, project='unused project', maxResults='unused',
1600
+ filter='unused'):
1601
+ return mock_api.MockRequest({'items': [{'name': 'a'},
1602
+ {'name': 'b'}]})
1603
+
1604
+ class GlobalAndZoneListMockCommand(CommandBaseTest.ListMockCommandBase):
1605
+ """A list mock command that represents a zone-scoped collection."""
1606
+ is_global_level_collection = True
1607
+ is_zone_level_collection = True
1608
+
1609
+ def __init__(self, name, flag_values):
1610
+ super(CommandBaseTest.ListMockCommandBase, self).__init__(name,
1611
+ flag_values)
1612
+ flags.DEFINE_string('zone',
1613
+ None,
1614
+ 'The zone to list.',
1615
+ flag_values=flag_values)
1616
+
1617
+ def ListZoneFunc(self):
1618
+ def Func(project=None, maxResults=None, filter=None, pageToken=None,
1619
+ zone=None):
1620
+ if zone == 'a':
1621
+ return mock_api.MockRequest(list_a)
1622
+ else:
1623
+ return mock_api.MockRequest(list_b)
1624
+ return Func
1625
+
1626
+ def ListFunc(self):
1627
+ def Func(project=None, maxResults=None, filter=None, pageToken=None):
1628
+ return mock_api.MockRequest(list_global)
1629
+ return Func
1630
+
1631
+ command = GlobalAndZoneListMockCommand('mock_command', flag_values)
1632
+ command._zones_api = LocalMockZonesApi()
1633
+
1634
+ # Test single zone
1635
+ flag_values.zone = 'a'
1636
+ command.SetFlags(flag_values)
1637
+ self.assertEqual(list_a, command.Handle())
1638
+
1639
+ # Test 'global' zone
1640
+ flag_values.zone = 'global'
1641
+ command.SetFlags(flag_values)
1642
+ self.assertEqual(list_global, command.Handle())
1643
+
1644
+ # Test all
1645
+ flag_values.zone = None
1646
+ command.SetFlags(flag_values)
1647
+ self.assertEqual(list_all, command.Handle())
1648
+
1649
+
1650
+ if __name__ == '__main__':
1651
+ unittest.main()