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

Side by Side Diff: test/lib/TestGyp.py

Issue 321953005: [gyp][Android] Implement TestGypAndroid.run_built_executable. (Closed) Base URL: http://gyp.googlecode.com/svn/trunk
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 Google Inc. All rights reserved. 1 # Copyright (c) 2012 Google Inc. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """ 5 """
6 TestGyp.py: a testing framework for GYP integration tests. 6 TestGyp.py: a testing framework for GYP integration tests.
7 """ 7 """
8 8
9 import collections 9 import collections
10 from contextlib import contextmanager 10 from contextlib import contextmanager
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 399
400 def __init__(self, gyp=None, *args, **kw): 400 def __init__(self, gyp=None, *args, **kw):
401 self.format = kw.pop("format") 401 self.format = kw.pop("format")
402 super(TestGypCustom, self).__init__(*args, **kw) 402 super(TestGypCustom, self).__init__(*args, **kw)
403 403
404 404
405 class TestGypAndroid(TestGypBase): 405 class TestGypAndroid(TestGypBase):
406 """ 406 """
407 Subclass for testing the GYP Android makefile generator. Note that 407 Subclass for testing the GYP Android makefile generator. Note that
408 build/envsetup.sh and lunch must have been run before running tests. 408 build/envsetup.sh and lunch must have been run before running tests.
409
410 TODO: This is currently an incomplete implementation. We do not support
411 run_built_executable(), so we pass only tests which do not use this. As a
412 result, support for host targets is not properly tested.
413 """ 409 """
414 format = 'android' 410 format = 'android'
415 411
416 # Note that we can't use mmm as the build tool because ... 412 # Note that we can't use mmm as the build tool because ...
417 # - it builds all targets, whereas we need to pass a target 413 # - it builds all targets, whereas we need to pass a target
418 # - it is a function, whereas the test runner assumes the build tool is a file 414 # - it is a function, whereas the test runner assumes the build tool is a file
419 # Instead we use make and duplicate the logic from mmm. 415 # Instead we use make and duplicate the logic from mmm.
420 build_tool_list = ['make'] 416 build_tool_list = ['make']
421 417
422 # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules' 418 # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules'
(...skipping 22 matching lines...) Expand all
445 for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']: 441 for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']:
446 for d in os.listdir(os.path.join(obj_dir, x)): 442 for d in os.listdir(os.path.join(obj_dir, x)):
447 if d.endswith('_gyp_intermediates'): 443 if d.endswith('_gyp_intermediates'):
448 shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True) 444 shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True)
449 for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]: 445 for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]:
450 for d in os.listdir(os.path.join(out_dir, x)): 446 for d in os.listdir(os.path.join(out_dir, x)):
451 if d.endswith('_gyp.so'): 447 if d.endswith('_gyp.so'):
452 os.remove(os.path.join(out_dir, x, d)) 448 os.remove(os.path.join(out_dir, x, d))
453 449
454 super(TestGypAndroid, self).__init__(*args, **kw) 450 super(TestGypAndroid, self).__init__(*args, **kw)
451 self._adb_path = os.path.join(os.environ['ANDROID_HOST_OUT'], 'bin', 'adb')
452 self._device_serial = None
453 adb_devices_out = self._call_adb(['devices'])
454 devices = [l.split()[0] for l in adb_devices_out.splitlines()[1:-1]
455 if l.split()[1] == 'device']
456 if len(devices) == 0:
457 self._device_serial = None
458 else:
459 if len(devices) > 1:
460 self._device_serial = random.choice(devices)
461 else:
462 self._device_serial = devices[0]
463 self._call_adb(['root'])
464 self._to_install = []
455 465
456 def target_name(self, target): 466 def target_name(self, target):
457 if target == self.ALL: 467 if target == self.ALL:
458 return self.ALL 468 return self.ALL
459 # The default target is 'droid'. However, we want to use our special target 469 # The default target is 'droid'. However, we want to use our special target
460 # to build only the gyp target 'all'. 470 # to build only the gyp target 'all'.
461 if target in (None, self.DEFAULT): 471 if target in (None, self.DEFAULT):
462 return self.ALL 472 return self.ALL
463 return target 473 return target
464 474
475 _installable_target_regex = re.compile('target Strip:\s*\S+\s+\((\S+)\)')
476
465 def build(self, gyp_file, target=None, **kw): 477 def build(self, gyp_file, target=None, **kw):
466 """ 478 """
467 Runs a build using the Android makefiles generated from the specified 479 Runs a build using the Android makefiles generated from the specified
468 gyp_file. This logic is taken from Android's mmm. 480 gyp_file. This logic is taken from Android's mmm.
469 """ 481 """
470 arguments = kw.get('arguments', [])[:] 482 arguments = kw.get('arguments', [])[:]
471 arguments.append(self.target_name(target)) 483 arguments.append(self.target_name(target))
472 arguments.append('-C') 484 arguments.append('-C')
473 arguments.append(os.environ['ANDROID_BUILD_TOP']) 485 arguments.append(os.environ['ANDROID_BUILD_TOP'])
474 kw['arguments'] = arguments 486 kw['arguments'] = arguments
475 chdir = kw.get('chdir', '') 487 chdir = kw.get('chdir', '')
476 makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk') 488 makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk')
477 os.environ['ONE_SHOT_MAKEFILE'] = makefile 489 os.environ['ONE_SHOT_MAKEFILE'] = makefile
478 result = self.run(program=self.build_tool, **kw) 490 result = self.run(program=self.build_tool, **kw)
491 for l in self.stdout().splitlines():
492 target_result = TestGypAndroid._installable_target_regex.match(l)
493 if target_result:
494 self._to_install.append(os.path.abspath(os.path.join(
495 os.environ['ANDROID_BUILD_TOP'], target_result.group(1))))
479 del os.environ['ONE_SHOT_MAKEFILE'] 496 del os.environ['ONE_SHOT_MAKEFILE']
480 return result 497 return result
481 498
482 def android_module(self, group, name, subdir): 499 def android_module(self, group, name, subdir):
483 if subdir: 500 if subdir:
484 name = '%s_%s' % (subdir, name) 501 name = '%s_%s' % (subdir, name)
485 if group == 'SHARED_LIBRARIES': 502 if group == 'SHARED_LIBRARIES':
486 name = 'lib_%s' % name 503 name = 'lib_%s' % name
487 return '%s_gyp' % name 504 return '%s_gyp' % name
488 505
(...skipping 23 matching lines...) Expand all
512 module_name = self.android_module(group, name, subdir) 529 module_name = self.android_module(group, name, subdir)
513 return os.path.join(self.intermediates_dir(group, module_name), 530 return os.path.join(self.intermediates_dir(group, module_name),
514 '%s.a' % module_name) 531 '%s.a' % module_name)
515 if type == self.SHARED_LIB: 532 if type == self.SHARED_LIB:
516 group = 'SHARED_LIBRARIES' 533 group = 'SHARED_LIBRARIES'
517 module_name = self.android_module(group, name, subdir) 534 module_name = self.android_module(group, name, subdir)
518 return os.path.join(self.intermediates_dir(group, module_name), 'LINKED', 535 return os.path.join(self.intermediates_dir(group, module_name), 'LINKED',
519 '%s.so' % module_name) 536 '%s.so' % module_name)
520 assert False, 'Unhandled type' 537 assert False, 'Unhandled type'
521 538
539 def _call_adb(self, command):
540 """ Calls the provided adb command.
541
542 If the command fails, the test fails.
543
544 Args:
545 command: The adb command to call.
546 Returns:
547 The command's output.
548 """
549 with tempfile.TemporaryFile(bufsize=0) as adb_out:
550 with tempfile.TemporaryFile(bufsize=0) as adb_err:
551 adb_command = [self._adb_path]
552 if self._device_serial:
553 adb_command += ['-s', self._device_serial]
554 adb_command += command
555 if subprocess.call(adb_command, stdout=adb_out, stderr=adb_err) != 0:
jbudorick 2014/06/11 16:30:22 (tests should fail here for nonzero exit codes)
556 print '%s failed:' % ' '.join(adb_command)
557 print self.banner('STDOUT ')
558 adb_out.seek(0)
559 print adb_out.read()
560 print self.banner('STDERR ')
561 adb_err.seek(0)
562 print adb_err.read()
563 self.fail_test()
564 else:
565 adb_out.seek(0)
566 output = adb_out.read()
567 return output
568
522 def run_built_executable(self, name, *args, **kw): 569 def run_built_executable(self, name, *args, **kw):
523 """ 570 """
524 Runs an executable program built from a gyp-generated configuration. 571 Runs an executable program built from a gyp-generated configuration.
572 """
573 match = kw.pop('match', self.match)
525 574
526 This is not correctly implemented for Android. For now, we simply check 575 executable_file = self.built_file_path(name, type=self.EXECUTABLE, **kw)
527 that the executable file exists. 576 if executable_file not in self._to_install:
528 """ 577 self.fail_test()
529 # Running executables requires a device. Even if we build for target x86,
530 # the binary is not built with the correct toolchain options to actually
531 # run on the host.
532 578
533 # Copied from TestCommon.run() 579 if not self._device_serial:
534 match = kw.pop('match', self.match) 580 self.skip_test(message='No devices attached.\n')
535 status = None 581
536 if os.path.exists(self.built_file_path(name)): 582 storage = self._call_adb(['shell', 'echo', '$ANDROID_DATA']).strip()
537 status = 1 583 if not len(storage):
538 self._complete(None, None, None, None, status, match) 584 self.fail_test()
585
586 installed = []
587 try:
588 for i in self._to_install:
589 a = os.path.abspath(
590 os.path.join(os.environ['ANDROID_BUILD_TOP'], i))
591 dest = '%s/%s' % (storage, os.path.basename(a))
592 self._call_adb(['push', os.path.abspath(a), dest])
593 installed.append(dest)
594 if i == executable_file:
595 device_executable = dest
596 self._call_adb(['shell', 'chmod', '755', device_executable])
597
598 out = self._call_adb(
599 ['shell', 'LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s' % storage,
600 device_executable])
601 out = out.replace('\r\n', '\n')
602 self._complete(out, kw.pop('stdout', None), None, None, None, match)
Torne 2014/06/11 12:44:18 Is there a way to return the program's exit status
jbudorick 2014/06/11 16:30:22 If a program exits with a nonzero exit code, _call
Torne 2014/06/11 16:41:39 adb does not return the error code of the program
603 finally:
604 if len(installed):
605 self._call_adb(['shell', 'rm'] + installed)
539 606
540 def match_single_line(self, lines = None, expected_line = None): 607 def match_single_line(self, lines = None, expected_line = None):
541 """ 608 """
542 Checks that specified line appears in the text. 609 Checks that specified line appears in the text.
543 """ 610 """
544 for line in lines.split('\n'): 611 for line in lines.split('\n'):
545 if line == expected_line: 612 if line == expected_line:
546 return 1 613 return 1
547 return 614 return
548 615
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 1287
1221 def TestGyp(*args, **kw): 1288 def TestGyp(*args, **kw):
1222 """ 1289 """
1223 Returns an appropriate TestGyp* instance for a specified GYP format. 1290 Returns an appropriate TestGyp* instance for a specified GYP format.
1224 """ 1291 """
1225 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) 1292 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
1226 for format_class in format_class_list: 1293 for format_class in format_class_list:
1227 if format == format_class.format: 1294 if format == format_class.format:
1228 return format_class(*args, **kw) 1295 return format_class(*args, **kw)
1229 raise Exception, "unknown format %r" % format 1296 raise Exception, "unknown format %r" % format
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698