-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtns.py
500 lines (445 loc) · 23.1 KB
/
tns.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
"""
A wrapper of tns commands.
"""
import os
import time
from core.osutils.command import run
from core.osutils.file import File
from core.osutils.folder import Folder
from core.osutils.os_type import OSType
from core.settings.settings import TNS_PATH, SUT_FOLDER, DEVELOPMENT_TEAM, BRANCH, TEST_RUN_HOME, \
COMMAND_TIMEOUT, CURRENT_OS
from core.settings.strings import config_release, codesign, config_debug
from core.tns.tns_platform_type import Platform
from core.tns.tns_verifications import TnsAsserts
from core.xcode.xcode import Xcode
class Tns(object):
# npm tag used when we publish master branch of https://github.com/NativeScript/NativeScript
# Please see https://github.com/NativeScript/NativeScript/blob/master/.travis.yml
NEXT_TAG = 'rc'
@staticmethod
def __get_platform_string(platform=Platform.NONE):
if platform is Platform.NONE:
return ""
if platform is Platform.ANDROID:
return "android"
if platform is Platform.IOS:
return "ios"
return platform
@staticmethod
def __get_final_package_name(app_name, platform=Platform.NONE):
"""
Get base name of final package (without extension and `-debug`, `-release` strings).
:param app_name: Folder where application is located.
:param platform: Platform (ANDROID or IOS)
:return:
"""
# Android respect id in package.json
# iOS respect folder name
# See https://github.com/NativeScript/nativescript-cli/issues/2575
if platform is Platform.ANDROID:
app_id = Tns.get_app_id(app_name)
# We can't get last with [-1] because some apps have wrong format of id.
# For example: `org.nativescript.demo.barcodescanner`
# In this case we should retrun `demo` as final package name.
return app_id.split('.')[2]
elif platform is Platform.IOS:
return app_name.replace(" ", "").replace("-", "").replace("_", "").replace("\"", "")
else:
raise "Invalid platform!"
@staticmethod
def __get_app_name_from_attributes(attributes={}):
app_name = ""
for k, v in attributes.iteritems():
if k == "--path":
app_name = v
return app_name
@staticmethod
def get_app_id(app_name):
"""
Get application id from package.json
:param app_name: Folder where application is located.
:return: Application id.
"""
json = TnsAsserts.get_package_json(app_name)
return json.get('nativescript').get('id')
@staticmethod
def run_tns_command(command, tns_path=None, attributes={}, log_trace=False, timeout=COMMAND_TIMEOUT, wait=True):
cmd = TNS_PATH + " " + command
if tns_path is not None:
cmd = tns_path + " " + command
if len(attributes) != 0:
for k, v in attributes.iteritems():
cmd += " " + k + " " + v
if log_trace:
cmd += " --log trace"
print cmd
output = run(command=cmd, timeout=timeout, wait=wait)
return output
@staticmethod
def update_modules(path, tns_path=None):
"""
Update modules for {N} project
:param path: Path to {N} project
:param tns_path: Path to tns executable
:return: Output of command that update tns-core-modules plugin.
"""
# Escape path with spaces
if " " in path:
path = "\"" + path + "\""
# In release branch we get modules versions from MODULES_VERSION variable.
# To prevent errors in local testing when it is not specified default value is set to be same as CLI version.
if "release" in BRANCH.lower():
cli_version = Tns.run_tns_command("", attributes={"--version": ""}, tns_path=tns_path)
version = os.environ.get("MODULES_VERSION", cli_version)
Tns.plugin_remove("tns-core-modules", attributes={"--path": path}, assert_success=False, tns_path=tns_path)
output = Tns.plugin_add("tns-core-modules@" + version, attributes={"--path": path}, assert_success=False,
tns_path=tns_path)
# In master branch we use @next packages.
else:
Tns.plugin_remove("tns-core-modules", attributes={"--path": path}, assert_success=False, tns_path=tns_path)
output = Tns.plugin_add("tns-core-modules@" + Tns.NEXT_TAG, attributes={"--path": path}, tns_path=tns_path)
assert "undefined" not in output, "Something went wrong when modules are installed."
assert "ERR" not in output, "Something went wrong when modules are installed."
return output
@staticmethod
def ensure_app_resources(path):
app_resources_path = os.path.join(path, "app", "App_Resources")
if File.exists(app_resources_path):
pass
else:
print "AppResources not found. Will copy from default template..."
src = os.path.join(TEST_RUN_HOME, "sut", "template-hello-world", "App_Resources")
dest = os.path.join(TEST_RUN_HOME, path, "app", "App_Resources")
Folder.copy(src, dest)
@staticmethod
def create_app(app_name, attributes={}, log_trace=False, assert_success=True, update_modules=True,
force_clean=True):
if force_clean:
if File.exists(app_name):
Folder.cleanup(app_name)
path = app_name
attributes_to_string = ""
for k, v in attributes.iteritems():
if "--path" in k:
path = v
attributes_to_string = "".join("{0} {1}".format(k, v))
attr = {}
if not any(s in attributes_to_string for s in ("--ng", "--template", "--tsc")):
attr = {"--template": SUT_FOLDER + os.path.sep + "template-hello-world"}
attr.update(attributes)
if app_name is None:
output = Tns.run_tns_command("create ", attributes=attr, log_trace=log_trace)
else:
output = Tns.run_tns_command("create \"" + app_name + "\"", attributes=attr, log_trace=log_trace)
if assert_success:
TnsAsserts.created(app_name=app_name, output=output)
if update_modules:
Tns.update_modules(path)
Tns.ensure_app_resources(path)
return output
@staticmethod
def create_app_ts(app_name, attributes={}, log_trace=False, assert_success=True, update_modules=True):
"""
Create TypeScript application based on hello-world-ts template in GitHub (branch is respected)
:param app_name: Application name.
:param attributes: Additional attributes for `tns create` command.
:param log_trace: If true runs with `--log trace`.
:param assert_success: If true application is verified once it is created.
:param update_modules: If true update modules (branch is respected).
:return: output of `tns create command`
"""
attr = {"--template": SUT_FOLDER + os.path.sep + "template-hello-world-ts"}
attributes.update(attr)
output = Tns.create_app(app_name=app_name, attributes=attributes, log_trace=log_trace,
assert_success=assert_success,
update_modules=update_modules)
if assert_success:
TnsAsserts.created_ts(app_name=app_name, output=output)
return output
@staticmethod
def create_app_ng(app_name, attributes={}, log_trace=False, assert_success=True, update_modules=True,
template_version=None):
if template_version is not None:
template = "tns-template-hello-world-ng@" + template_version
attr = {"--template": template}
else:
attr = {"--template": SUT_FOLDER + os.path.sep + "template-hello-world-ng"}
attributes.update(attr)
output = Tns.create_app(app_name=app_name, attributes=attributes, log_trace=log_trace,
assert_success=assert_success,
update_modules=update_modules)
if assert_success:
assert "nativescript-angular" in output
return output
@staticmethod
def platform_add(platform=Platform.NONE, version=None, attributes={}, assert_success=True, log_trace=False,
tns_path=None):
#######################################################################################
# Add platforms
#######################################################################################
platform_string = Tns.__get_platform_string(platform)
if version is not None:
platform_string = platform_string + "@" + version
output = Tns.run_tns_command("platform add " + platform_string, attributes=attributes, log_trace=log_trace,
tns_path=tns_path)
#######################################################################################
# Verify platforms added (if assert_success=True)
#######################################################################################
app_name = Tns.__get_app_name_from_attributes(attributes)
if assert_success:
TnsAsserts.platform_added(app_name=app_name, platform=platform, output=output)
return output
@staticmethod
def platform_remove(platform=Platform.NONE, attributes={}, assert_success=True, log_trace=False, tns_path=None):
platform_string = Tns.__get_platform_string(platform)
output = Tns.run_tns_command("platform remove " + platform_string, attributes=attributes, log_trace=log_trace,
tns_path=tns_path)
app_name = Tns.__get_app_name_from_attributes(attributes)
if assert_success:
assert "Platform {0} successfully removed".format(platform_string) in output
assert "error" not in output
if platform is Platform.ANDROID:
assert not File.exists(app_name + TnsAsserts.PLATFORM_ANDROID)
if platform is Platform.IOS:
assert not File.exists(app_name + TnsAsserts.IOS)
return output
@staticmethod
def platform_clean(platform=Platform.NONE, attributes={}, assert_success=True, log_trace=False, tns_path=None):
platform_string = Tns.__get_platform_string(platform)
output = Tns.run_tns_command("platform clean " + platform_string, attributes=attributes, log_trace=log_trace,
tns_path=tns_path)
app_name = Tns.__get_app_name_from_attributes(attributes)
if assert_success:
assert "Platform {0} successfully removed".format(platform_string) in output
assert "error" not in output
if platform is Platform.ANDROID:
assert File.exists(app_name + TnsAsserts.PLATFORM_ANDROID)
if platform is Platform.IOS:
assert File.exists(app_name + TnsAsserts.IOS)
assert "Project successfully created" in output
return output
@staticmethod
def platform_update(platform=Platform.NONE, version=None, attributes={}, assert_success=True, log_trace=False,
tns_path=None):
platform_string = Tns.__get_platform_string(platform)
if version is not None:
platform_string = platform_string + "@" + version
output = Tns.run_tns_command("platform update " + platform_string, attributes=attributes, log_trace=log_trace,
tns_path=tns_path)
if assert_success:
assert "Successfully updated to version" in output, "Failed to update platform. Log: " + output
return output
@staticmethod
def platform_add_android(version=None, attributes={}, assert_success=True, log_trace=False, tns_path=None):
return Tns.platform_add(platform=Platform.ANDROID, version=version, attributes=attributes,
assert_success=assert_success,
log_trace=log_trace,
tns_path=tns_path)
@staticmethod
def platform_add_ios(version=None, attributes={}, assert_success=True, log_trace=False, tns_path=None):
return Tns.platform_add(Platform.IOS, version=version, attributes=attributes, assert_success=assert_success,
log_trace=log_trace,
tns_path=tns_path)
@staticmethod
def platform_list(attributes={}, assert_success=True, log_trace=False, tns_path=None):
return Tns.run_tns_command("platform list", attributes=attributes, log_trace=log_trace, tns_path=tns_path)
@staticmethod
def plugin_add(name, attributes={}, log_trace=False, assert_success=True, tns_path=None):
output = Tns.run_tns_command("plugin add " + name, attributes=attributes, log_trace=log_trace,
tns_path=tns_path)
if assert_success:
assert "Successfully installed plugin {0}".format(name.replace("@" + Tns.NEXT_TAG, "")) in output
return output
@staticmethod
def plugin_remove(name, attributes={}, log_trace=False, assert_success=True, tns_path=None):
output = Tns.run_tns_command("plugin remove " + name, attributes=attributes, log_trace=log_trace,
tns_path=tns_path)
if assert_success:
assert "Successfully removed plugin {0}".format(name.replace("@" + Tns.NEXT_TAG, "")) in output
return output
@staticmethod
def prepare_android(attributes={}, assert_success=True, log_trace=False, tns_path=None):
output = Tns.run_tns_command("prepare android ", attributes=attributes, log_trace=log_trace, tns_path=tns_path)
if assert_success:
assert "Project successfully prepared" in output
return output
@staticmethod
def prepare_ios(attributes={}, assert_success=True, log_trace=False, tns_path=None):
output = Tns.run_tns_command("prepare ios ", attributes=attributes, log_trace=log_trace, tns_path=tns_path)
if assert_success:
assert "Project successfully prepared" in output
return output
@staticmethod
def build_android(attributes={}, assert_success=True, tns_path=None):
output = Tns.run_tns_command("build android", attributes=attributes, tns_path=tns_path)
if assert_success:
assert "BUILD SUCCESSFUL" in output, "Build failed!"
assert "Project successfully built" in output, "Build failed!"
assert "NOT FOUND" not in output # Test for https://github.com/NativeScript/android-runtime/issues/390
app_name = Tns.__get_app_name_from_attributes(attributes=attributes)
apk_base_name = Tns.__get_final_package_name(app_name, platform=Platform.ANDROID)
base_app_path = app_name + TnsAsserts.PLATFORM_ANDROID + "build/outputs/apk/" + apk_base_name
if "--release" in attributes.keys():
apk_path = base_app_path + "-release.apk"
else:
apk_path = base_app_path + "-debug.apk"
apk_path = apk_path.replace("\"", "") # Handle projects with space
assert File.exists(apk_path), "Apk file does not exist at " + apk_path
return output
@staticmethod
def build_ios(attributes={}, assert_success=True, tns_path=None):
if "8." in Xcode.get_version():
# TODO: Use "--provision" instead.
attr = {"--teamId": DEVELOPMENT_TEAM}
attributes.update(attr)
output = Tns.run_tns_command("build ios", attributes=attributes, tns_path=tns_path)
if assert_success:
assert "BUILD SUCCEEDED" in output
assert "Project successfully built" in output
assert "ERROR" not in output
assert "malformed" not in output
assert codesign in output
app_name = Tns.__get_app_name_from_attributes(attributes=attributes)
app_id = Tns.__get_final_package_name(app_name, platform=Platform.IOS)
app_name = app_name.replace("\"", "") # Handle projects with space
# Verify release/debug builds
if "--release" in attributes.keys():
assert config_release in output
else:
assert config_debug in output
# Verify simulator/device builds
device_folder = app_name + "/platforms/ios/build/device/"
emu_folder = app_name + "/platforms/ios/build/emulator/"
if "--forDevice" in attributes.keys() or "--for-device" in attributes.keys():
assert "build/device/" + app_id + ".app" in output
assert File.exists(device_folder + app_id + ".ipa")
output = File.read(device_folder + app_id + ".app/" + app_id)
if "--release" in attributes.keys():
assert "TKLiveSync" not in output, "TKLiveSync binaries available in release configuration."
else:
assert "TKLiveSync" in output, "TKLiveSync binaries not available in debug configuration."
else:
assert "build/emulator/" + app_id + ".app" in output
assert File.exists(app_name + "/platforms/ios/" + app_id + "/" + app_id + "-Prefix.pch")
assert File.exists(emu_folder + app_id + ".app")
output = File.read(emu_folder + app_id + ".app/" + app_id)
if "--release" in attributes.keys():
assert "TKLiveSync" not in output, "TKLiveSync binaries available in release configuration."
else:
assert "TKLiveSync" in output, "TKLiveSync binaries not available in debug configuration."
return output
@staticmethod
def deploy_android(attributes={}, assert_success=True, log_trace=False, timeout=COMMAND_TIMEOUT, tns_path=None):
output = Tns.run_tns_command("deploy android", attributes=attributes, log_trace=log_trace, timeout=timeout,
tns_path=tns_path)
if assert_success:
assert "Project successfully built" in output
assert "Successfully installed on device" in output
return output
@staticmethod
def deploy_ios(attributes={}, assert_success=True, log_trace=False, timeout=COMMAND_TIMEOUT, tns_path=None):
if "8." in Xcode.get_version():
attr = {"--teamId": DEVELOPMENT_TEAM}
attributes.update(attr)
output = Tns.run_tns_command("deploy ios", attributes=attributes, log_trace=log_trace, timeout=timeout,
tns_path=tns_path)
if assert_success:
assert "Project successfully built" in output
assert "Successfully installed on device" in output
return output
@staticmethod
def run_android(attributes={}, assert_success=True, log_trace=False, timeout=COMMAND_TIMEOUT, tns_path=None,
wait=True):
output = Tns.run_tns_command("run android", attributes=attributes, log_trace=log_trace, timeout=timeout,
tns_path=tns_path, wait=wait)
if assert_success:
assert "Project successfully built" in output
assert "Successfully installed on device with identifier" in output
return output
@staticmethod
def run_ios(attributes={}, assert_success=True, log_trace=False, timeout=COMMAND_TIMEOUT, tns_path=None, wait=True):
if "8." in Xcode.get_version():
attr = {"--teamId": DEVELOPMENT_TEAM}
attributes.update(attr)
output = Tns.run_tns_command("run ios", attributes=attributes, log_trace=log_trace, timeout=timeout,
tns_path=tns_path, wait=wait)
if assert_success:
assert "Project successfully built" in output
assert "Successfully installed on device with identifier" in output
return output
@staticmethod
def debug_android(attributes={}, assert_success=True, log_trace=False, timeout=COMMAND_TIMEOUT, tns_path=None,
wait=True):
log_file = Tns.run_tns_command("debug android", attributes=attributes, log_trace=log_trace, timeout=timeout,
tns_path=tns_path, wait=False)
return log_file
@staticmethod
def debug_ios(attributes={}, log_trace=False, timeout=COMMAND_TIMEOUT, tns_path=None):
log_file = Tns.run_tns_command("debug ios", attributes=attributes, log_trace=log_trace, timeout=timeout,
tns_path=tns_path, wait=False)
return log_file
@staticmethod
def init(attributes={}, assert_success=True, tns_path=None):
output = Tns.run_tns_command("init", attributes=attributes, tns_path=tns_path)
if assert_success:
assert "Project successfully initialized" in output
return output
@staticmethod
def install(attributes={}, assert_success=True, tns_path=None):
output = Tns.run_tns_command("install", attributes=attributes, tns_path=tns_path)
if assert_success:
assert "Project successfully created" in output
return output
@staticmethod
def disable_reporting():
Tns.run_tns_command("usage-reporting disable")
Tns.run_tns_command("error-reporting disable")
@staticmethod
def wait_for_log(log_file, string_list, timeout=30, check_interval=3, clean_log=True):
"""
Wait until log file contains list of string.
:param log_file: Path to log file.
:param string_list: List of strings.
:param timeout: Timeout.
:param check_interval: Check interval.
:param clean_log: Specify if content of log file should be delete after check.
"""
t_end = time.time() + timeout
all_items_found = False
not_found_list = []
log = ""
while time.time() < t_end:
not_found_list = []
log = File.read(log_file)
for item in string_list:
if item in log:
print "'{0}' found.".format(item)
else:
not_found_list.append(item)
if not_found_list == []:
all_items_found = True
print "Log contains: {0}".format(string_list)
break
else:
print "'{0}' NOT found. Wait...".format(not_found_list)
time.sleep(check_interval)
if 'BUILD FAILED' in log:
print 'BUILD FAILED. No need to wait more time!'
break
if 'Unable to sync files' in log:
print 'Sync process failed. No need to wait more time!'
break
if 'errors were thrown' in log:
print 'Multiple errors were thrown. No need to wait more time!'
break
if clean_log and (CURRENT_OS is not OSType.WINDOWS) and all_items_found:
File.write(file_path=log_file, text="")
if all_items_found:
pass
else:
print "##### OUTPUT BEGIN #####\n"
print log
print "##### OUTPUT END #####\n"
print ""
assert False, "Output does not contain {0}".format(not_found_list)