Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aws
GitHub Repository: aws/aws-cli
Path: blob/develop/tests/unit/customizations/gamelift/test_uploadbuild.py
2632 views
1
# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License"). You
4
# may not use this file except in compliance with the License. A copy of
5
# the License is located at
6
#
7
# http://aws.amazon.com/apache2.0/
8
#
9
# or in the "license" file accompanying this file. This file is
10
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
# ANY KIND, either express or implied. See the License for the specific
12
# language governing permissions and limitations under the License.
13
from argparse import Namespace
14
import contextlib
15
import os
16
import zipfile
17
18
from botocore.session import get_session
19
from botocore.exceptions import ClientError
20
21
from awscli.testutils import unittest, mock, FileCreator
22
from awscli.customizations.gamelift.uploadbuild import UploadBuildCommand
23
from awscli.customizations.gamelift.uploadbuild import zip_directory
24
from awscli.customizations.gamelift.uploadbuild import validate_directory
25
from awscli.customizations.gamelift.uploadbuild import parse_tags
26
from awscli.compat import StringIO
27
28
29
class TestGetGameSessionLogCommand(unittest.TestCase):
30
def setUp(self):
31
self.create_client_patch = mock.patch(
32
'botocore.session.Session.create_client')
33
self.mock_create_client = self.create_client_patch.start()
34
self.session = get_session()
35
36
self.gamelift_client = mock.Mock()
37
self.s3_client = mock.Mock()
38
self.mock_create_client.side_effect = [
39
self.gamelift_client, self.s3_client
40
]
41
42
self.file_creator = FileCreator()
43
self.upload_file_patch = mock.patch(
44
'awscli.customizations.gamelift.uploadbuild.S3Transfer.upload_file'
45
)
46
self.upload_file_mock = self.upload_file_patch.start()
47
48
self.cmd = UploadBuildCommand(self.session)
49
self._setup_input_output()
50
51
def tearDown(self):
52
self.create_client_patch.stop()
53
self.file_creator.remove_all()
54
self.upload_file_patch.stop()
55
56
def _setup_input_output(self):
57
# Input values
58
self.region = 'us-west-2'
59
self.build_name = 'mybuild'
60
self.build_version = 'myversion'
61
self.build_root = self.file_creator.rootdir
62
63
self.args = [
64
'--name', self.build_name, '--build-version', self.build_version,
65
'--build-root', self.build_root
66
]
67
68
self.global_args = Namespace()
69
self.global_args.region = self.region
70
self.global_args.endpoint_url = None
71
self.global_args.verify_ssl = None
72
73
# Output values
74
self.build_id = 'myid'
75
self.bucket = 'mybucket'
76
self.key = 'mykey'
77
self.access_key = 'myaccesskey'
78
self.secret_key = 'mysecretkey'
79
self.session_token = 'mytoken'
80
81
self.gamelift_client.create_build.return_value = {
82
'Build': {
83
'BuildId': self.build_id
84
}
85
}
86
87
self.gamelift_client.request_upload_credentials.return_value = {
88
'StorageLocation': {
89
'Bucket': self.bucket,
90
'Key': self.key
91
},
92
'UploadCredentials': {
93
'AccessKeyId': self.access_key,
94
'SecretAccessKey': self.secret_key,
95
'SessionToken': self.session_token
96
}
97
}
98
99
def test_upload_build(self):
100
self.file_creator.create_file('tmpfile', 'Some contents')
101
self.cmd(self.args, self.global_args)
102
# Ensure the clients were instantiated correctly.
103
client_creation_args = self.mock_create_client.call_args_list
104
self.assertEqual(
105
client_creation_args,
106
[mock.call('gamelift', region_name=self.region,
107
endpoint_url=None, verify=None),
108
mock.call('s3', aws_access_key_id=self.access_key,
109
aws_secret_access_key=self.secret_key,
110
aws_session_token=self.session_token,
111
region_name=self.region,
112
verify=None)]
113
)
114
115
# Ensure the GameLift client was called correctly.
116
self.gamelift_client.create_build.assert_called_once_with(
117
Name=self.build_name, Version=self.build_version)
118
119
self.gamelift_client.request_upload_credentials.\
120
assert_called_once_with(BuildId=self.build_id)
121
122
# Ensure the underlying S3 transfer call was correct.
123
self.upload_file_mock.assert_called_once_with(
124
mock.ANY, self.bucket, self.key, callback=mock.ANY)
125
126
tempfile_path = self.upload_file_mock.call_args[0][0]
127
# Ensure the temporary zipfile is deleted at the end.
128
self.assertFalse(os.path.exists(tempfile_path))
129
130
def test_upload_build_when_operating_system_is_provided(self):
131
operating_system = 'WINDOWS_2012'
132
self.file_creator.create_file('tmpfile', 'Some contents')
133
self.args = [
134
'--name', self.build_name, '--build-version', self.build_version,
135
'--build-root', self.build_root,
136
'--operating-system', operating_system
137
]
138
self.cmd(self.args, self.global_args)
139
140
# Ensure the GameLift client was called correctly.
141
self.gamelift_client.create_build.assert_called_once_with(
142
Name=self.build_name, Version=self.build_version,
143
OperatingSystem=operating_system)
144
145
def test_error_message_when_directory_is_empty(self):
146
with mock.patch('sys.stderr', StringIO()) as mock_stderr:
147
self.cmd(self.args, self.global_args)
148
self.assertEqual(
149
mock_stderr.getvalue(),
150
f'Fail to upload {self.build_root}. '
151
'The build root directory is empty or does not exist.\n'
152
)
153
154
def test_error_message_when_directory_is_not_provided(self):
155
self.args = [
156
'--name', self.build_name,
157
'--build-version', self.build_version,
158
'--build-root', ''
159
]
160
161
with mock.patch('sys.stderr', StringIO()) as mock_stderr:
162
self.cmd(self.args, self.global_args)
163
self.assertEqual(
164
mock_stderr.getvalue(),
165
'Fail to upload {}. '
166
'The build root directory is empty or does not exist.\n'.format('')
167
)
168
169
def test_error_message_when_directory_does_not_exist(self):
170
dir_not_exist = os.path.join(self.build_root, 'does_not_exist')
171
172
self.args = [
173
'--name', self.build_name,
174
'--build-version', self.build_version,
175
'--build-root', dir_not_exist
176
]
177
178
with mock.patch('sys.stderr', StringIO()) as mock_stderr:
179
self.cmd(self.args, self.global_args)
180
self.assertEqual(
181
mock_stderr.getvalue(),
182
f'Fail to upload {dir_not_exist}. '
183
'The build root directory is empty or does not exist.\n'
184
)
185
186
def test_temporary_file_does_exist_when_fails(self):
187
self.upload_file_mock.side_effect = ClientError(
188
{'Error': {'Code': 403, 'Message': 'No Access'}}, 'PutObject')
189
with self.assertRaises(ClientError):
190
self.file_creator.create_file('tmpfile', 'Some contents')
191
self.cmd(self.args, self.global_args)
192
tempfile_path = self.upload_file_mock.call_args[0][0]
193
# Make sure the temporary file is removed.
194
self.assertFalse(os.path.exists(tempfile_path))
195
196
def test_upload_build_when_server_sdk_version_is_provided(self):
197
server_sdk_version = '4.0.2'
198
self.file_creator.create_file('tmpfile', 'Some contents')
199
self.args = [
200
'--name', self.build_name, '--build-version', self.build_version,
201
'--build-root', self.build_root,
202
'--server-sdk-version', server_sdk_version
203
]
204
self.cmd(self.args, self.global_args)
205
206
# Ensure the GameLift client was called correctly.
207
self.gamelift_client.create_build.assert_called_once_with(
208
Name=self.build_name, Version=self.build_version,
209
ServerSdkVersion=server_sdk_version)
210
211
def test_upload_build_when_tags_are_provided(self):
212
self.file_creator.create_file('tmpfile', 'Some contents')
213
self.args = [
214
'--name', self.build_name, '--build-version', self.build_version,
215
'--build-root', self.build_root,
216
'--tags', 'Environment=Production', 'Team=GameDev'
217
]
218
self.cmd(self.args, self.global_args)
219
220
self.gamelift_client.create_build.assert_called_once_with(
221
Name=self.build_name, Version=self.build_version,
222
Tags=[
223
{'Key': 'Environment', 'Value': 'Production'},
224
{'Key': 'Team', 'Value': 'GameDev'}
225
])
226
227
228
class TestParseTags(unittest.TestCase):
229
def test_parse_tags_with_key_value_pairs(self):
230
result = parse_tags(['Key1=Value1', 'Key2=Value2'])
231
self.assertEqual(result, [
232
{'Key': 'Key1', 'Value': 'Value1'},
233
{'Key': 'Key2', 'Value': 'Value2'}
234
])
235
236
def test_parse_tags_with_empty_value(self):
237
result = parse_tags(['Key1='])
238
self.assertEqual(result, [{'Key': 'Key1', 'Value': ''}])
239
240
def test_parse_tags_without_equals(self):
241
result = parse_tags(['Key1'])
242
self.assertEqual(result, [{'Key': 'Key1', 'Value': ''}])
243
244
def test_parse_tags_with_equals_in_value(self):
245
result = parse_tags(['Key1=Value=WithEquals'])
246
self.assertEqual(result, [{'Key': 'Key1', 'Value': 'Value=WithEquals'}])
247
248
def test_parse_tags_with_none(self):
249
result = parse_tags(None)
250
self.assertEqual(result, [])
251
252
def test_parse_tags_with_empty_list(self):
253
result = parse_tags([])
254
self.assertEqual(result, [])
255
256
257
class TestZipDirectory(unittest.TestCase):
258
def setUp(self):
259
self.file_creator = FileCreator()
260
self.zip_file = self.file_creator.create_file('build.zip', '')
261
self._dir_root = 'mybuild'
262
263
def tearDown(self):
264
self.file_creator.remove_all()
265
266
@property
267
def dir_root(self):
268
return self.file_creator.full_path(self._dir_root)
269
270
def add_to_directory(self, filename):
271
self.file_creator.create_file(
272
os.path.join(self._dir_root, filename), 'Some contents')
273
274
def assert_contents_of_zip_file(self, filenames):
275
zip_file_object = zipfile.ZipFile(
276
self.zip_file, 'r', zipfile.ZIP_DEFLATED)
277
with contextlib.closing(zip_file_object) as zf:
278
ref_zipfiles = []
279
zipfile_contents = zf.namelist()
280
for ref_zipfile in zipfile_contents:
281
if os.sep == '\\':
282
# Internally namelist() represent directories with
283
# forward slashes so we need to account for that if
284
# the separator is a backslash depending on the operating
285
# system.
286
ref_zipfile = ref_zipfile.replace('/', '\\')
287
ref_zipfiles.append(ref_zipfile)
288
self.assertEqual(sorted(ref_zipfiles), filenames)
289
290
def test_single_file(self):
291
self.add_to_directory('foo')
292
zip_directory(self.zip_file, self.dir_root)
293
self.assert_contents_of_zip_file(['foo'])
294
295
def test_multiple_files(self):
296
self.add_to_directory('foo')
297
self.add_to_directory('bar')
298
zip_directory(self.zip_file, self.dir_root)
299
self.assert_contents_of_zip_file(['bar', 'foo'])
300
301
def test_nested_file(self):
302
filename = os.path.join('mydir', 'foo')
303
self.add_to_directory(filename)
304
zip_directory(self.zip_file, self.dir_root)
305
self.assert_contents_of_zip_file([filename])
306
307
308
class TestValidateDirectory(unittest.TestCase):
309
def setUp(self):
310
self.file_creator = FileCreator()
311
self.dir_root = self.file_creator.rootdir
312
313
def tearDown(self):
314
self.file_creator.remove_all()
315
316
def test_directory_contains_single_file(self):
317
self.file_creator.create_file('foo', '')
318
self.assertTrue(validate_directory(self.dir_root))
319
320
def test_directory_contains_file_and_empty_directory(self):
321
dirname = os.path.join(self.dir_root, 'foo')
322
os.makedirs(dirname)
323
self.file_creator.create_file('bar', '')
324
self.assertTrue(validate_directory(self.dir_root))
325
326
def test_nested_file(self):
327
self.file_creator.create_file('mydir/bar', '')
328
self.assertTrue(validate_directory(self.dir_root))
329
330
def test_empty_directory(self):
331
self.assertFalse(validate_directory(self.dir_root))
332
333
def test_nonexistent_directory(self):
334
dir_not_exist = os.path.join(self.dir_root, 'does_not_exist')
335
self.assertFalse(validate_directory(dir_not_exist))
336
337
def test_nonprovided_directory(self):
338
self.assertFalse(validate_directory(''))
339
340
def test_empty_nested_directory(self):
341
dirname = os.path.join(self.dir_root, 'foo')
342
os.makedirs(dirname)
343
self.assertFalse(validate_directory(self.dir_root))
344
345