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

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
« no previous file with comments | « test/configurations/inheritance/gyptest-inheritance.py ('k') | test/library/gyptest-shared.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 402
403 def __init__(self, gyp=None, *args, **kw): 403 def __init__(self, gyp=None, *args, **kw):
404 self.format = kw.pop("format") 404 self.format = kw.pop("format")
405 super(TestGypCustom, self).__init__(*args, **kw) 405 super(TestGypCustom, self).__init__(*args, **kw)
406 406
407 407
408 class TestGypAndroid(TestGypBase): 408 class TestGypAndroid(TestGypBase):
409 """ 409 """
410 Subclass for testing the GYP Android makefile generator. Note that 410 Subclass for testing the GYP Android makefile generator. Note that
411 build/envsetup.sh and lunch must have been run before running tests. 411 build/envsetup.sh and lunch must have been run before running tests.
412
413 TODO: This is currently an incomplete implementation. We do not support
414 run_built_executable(), so we pass only tests which do not use this. As a
415 result, support for host targets is not properly tested.
416 """ 412 """
417 format = 'android' 413 format = 'android'
418 414
419 # Note that we can't use mmm as the build tool because ... 415 # Note that we can't use mmm as the build tool because ...
420 # - it builds all targets, whereas we need to pass a target 416 # - it builds all targets, whereas we need to pass a target
421 # - it is a function, whereas the test runner assumes the build tool is a file 417 # - it is a function, whereas the test runner assumes the build tool is a file
422 # Instead we use make and duplicate the logic from mmm. 418 # Instead we use make and duplicate the logic from mmm.
423 build_tool_list = ['make'] 419 build_tool_list = ['make']
424 420
425 # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules' 421 # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules'
(...skipping 22 matching lines...) Expand all
448 for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']: 444 for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']:
449 for d in os.listdir(os.path.join(obj_dir, x)): 445 for d in os.listdir(os.path.join(obj_dir, x)):
450 if d.endswith('_gyp_intermediates'): 446 if d.endswith('_gyp_intermediates'):
451 shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True) 447 shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True)
452 for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]: 448 for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]:
453 for d in os.listdir(os.path.join(out_dir, x)): 449 for d in os.listdir(os.path.join(out_dir, x)):
454 if d.endswith('_gyp.so'): 450 if d.endswith('_gyp.so'):
455 os.remove(os.path.join(out_dir, x, d)) 451 os.remove(os.path.join(out_dir, x, d))
456 452
457 super(TestGypAndroid, self).__init__(*args, **kw) 453 super(TestGypAndroid, self).__init__(*args, **kw)
454 self._adb_path = os.path.join(os.environ['ANDROID_HOST_OUT'], 'bin', 'adb')
455 self._device_serial = None
456 adb_devices_out = self._call_adb(['devices'])
457 devices = [l.split()[0] for l in adb_devices_out.splitlines()[1:-1]
458 if l.split()[1] == 'device']
459 if len(devices) == 0:
460 self._device_serial = None
461 else:
462 if len(devices) > 1:
463 self._device_serial = random.choice(devices)
464 else:
465 self._device_serial = devices[0]
466 self._call_adb(['root'])
467 self._to_install = set()
458 468
459 def target_name(self, target): 469 def target_name(self, target):
460 if target == self.ALL: 470 if target == self.ALL:
461 return self.ALL 471 return self.ALL
462 # The default target is 'droid'. However, we want to use our special target 472 # The default target is 'droid'. However, we want to use our special target
463 # to build only the gyp target 'all'. 473 # to build only the gyp target 'all'.
464 if target in (None, self.DEFAULT): 474 if target in (None, self.DEFAULT):
465 return self.ALL 475 return self.ALL
466 return target 476 return target
467 477
478 _INSTALLABLE_PREFIX = 'Install: '
479
468 def build(self, gyp_file, target=None, **kw): 480 def build(self, gyp_file, target=None, **kw):
469 """ 481 """
470 Runs a build using the Android makefiles generated from the specified 482 Runs a build using the Android makefiles generated from the specified
471 gyp_file. This logic is taken from Android's mmm. 483 gyp_file. This logic is taken from Android's mmm.
472 """ 484 """
473 arguments = kw.get('arguments', [])[:] 485 arguments = kw.get('arguments', [])[:]
474 arguments.append(self.target_name(target)) 486 arguments.append(self.target_name(target))
475 arguments.append('-C') 487 arguments.append('-C')
476 arguments.append(os.environ['ANDROID_BUILD_TOP']) 488 arguments.append(os.environ['ANDROID_BUILD_TOP'])
477 kw['arguments'] = arguments 489 kw['arguments'] = arguments
478 chdir = kw.get('chdir', '') 490 chdir = kw.get('chdir', '')
479 makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk') 491 makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk')
480 os.environ['ONE_SHOT_MAKEFILE'] = makefile 492 os.environ['ONE_SHOT_MAKEFILE'] = makefile
481 result = self.run(program=self.build_tool, **kw) 493 result = self.run(program=self.build_tool, **kw)
494 for l in self.stdout().splitlines():
495 if l.startswith(TestGypAndroid._INSTALLABLE_PREFIX):
496 self._to_install.add(os.path.abspath(os.path.join(
497 os.environ['ANDROID_BUILD_TOP'],
498 l[len(TestGypAndroid._INSTALLABLE_PREFIX):])))
482 del os.environ['ONE_SHOT_MAKEFILE'] 499 del os.environ['ONE_SHOT_MAKEFILE']
483 return result 500 return result
484 501
485 def android_module(self, group, name, subdir): 502 def android_module(self, group, name, subdir):
486 if subdir: 503 if subdir:
487 name = '%s_%s' % (subdir, name) 504 name = '%s_%s' % (subdir, name)
488 if group == 'SHARED_LIBRARIES': 505 if group == 'SHARED_LIBRARIES':
489 name = 'lib_%s' % name 506 name = 'lib_%s' % name
490 return '%s_gyp' % name 507 return '%s_gyp' % name
491 508
492 def intermediates_dir(self, group, module_name): 509 def intermediates_dir(self, group, module_name):
493 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group, 510 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group,
494 '%s_intermediates' % module_name) 511 '%s_intermediates' % module_name)
495 512
496 def built_file_path(self, name, type=None, **kw): 513 def built_file_path(self, name, type=None, **kw):
497 """ 514 """
498 Returns a path to the specified file name, of the specified type, 515 Returns a path to the specified file name, of the specified type,
499 as built by Android. Note that we don't support the configuration 516 as built by Android. Note that we don't support the configuration
500 parameter. 517 parameter.
501 """ 518 """
502 # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from 519 # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from
503 # the Android build system. 520 # the Android build system.
504 if type == None: 521 if type == None or type == self.EXECUTABLE:
505 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP', 522 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP',
506 'shared_intermediates', name) 523 'shared_intermediates', name)
507 subdir = kw.get('subdir') 524 subdir = kw.get('subdir')
508 if type == self.EXECUTABLE:
509 # We don't install executables
510 group = 'EXECUTABLES'
511 module_name = self.android_module(group, name, subdir)
512 return os.path.join(self.intermediates_dir(group, module_name), name)
513 if type == self.STATIC_LIB: 525 if type == self.STATIC_LIB:
514 group = 'STATIC_LIBRARIES' 526 group = 'STATIC_LIBRARIES'
515 module_name = self.android_module(group, name, subdir) 527 module_name = self.android_module(group, name, subdir)
516 return os.path.join(self.intermediates_dir(group, module_name), 528 return os.path.join(self.intermediates_dir(group, module_name),
517 '%s.a' % module_name) 529 '%s.a' % module_name)
518 if type == self.SHARED_LIB: 530 if type == self.SHARED_LIB:
519 group = 'SHARED_LIBRARIES' 531 group = 'SHARED_LIBRARIES'
520 module_name = self.android_module(group, name, subdir) 532 module_name = self.android_module(group, name, subdir)
521 return os.path.join(self.intermediates_dir(group, module_name), 'LINKED', 533 return os.path.join(self.intermediates_dir(group, module_name), 'LINKED',
522 '%s.so' % module_name) 534 '%s.so' % module_name)
523 assert False, 'Unhandled type' 535 assert False, 'Unhandled type'
524 536
537 def _adb_failure(self, command, msg, stdout, stderr):
538 """ Reports a failed adb command and fails the containing test.
539
540 Args:
541 command: The adb command that failed.
542 msg: The error description.
543 stdout: The standard output.
544 stderr: The standard error.
545 """
546 print '%s failed%s' % (' '.join(command), ': %s' % msg if msg else '')
547 print self.banner('STDOUT ')
548 stdout.seek(0)
549 print stdout.read()
550 print self.banner('STDERR ')
551 stderr.seek(0)
552 print stderr.read()
553 self.fail_test()
554
555 def _call_adb(self, command):
556 """ Calls the provided adb command.
557
558 If the command fails, the test fails.
559
560 Args:
561 command: The adb command to call.
562 Returns:
563 The command's output.
564 """
565 with tempfile.TemporaryFile(bufsize=0) as adb_out:
566 with tempfile.TemporaryFile(bufsize=0) as adb_err:
567 adb_command = [self._adb_path]
568 if self._device_serial:
569 adb_command += ['-s', self._device_serial]
570 is_shell = (command[0] == 'shell')
571 if is_shell:
572 command = [command[0], '%s; echo "\n$?";' % ' '.join(command[1:])]
573 adb_command += command
574 if subprocess.call(adb_command, stdout=adb_out, stderr=adb_err) != 0:
575 self._adb_failure(adb_command, None, adb_out, adb_err)
576 else:
577 adb_out.seek(0)
578 output = adb_out.read()
579 if is_shell:
580 output = output.splitlines(True)
581 try:
582 output[-2] = output[-2].rstrip('\r\n')
583 output, rc = (''.join(output[:-1]), int(output[-1]))
584 except ValueError:
585 self._adb_failure(adb_command, 'unexpected output format',
586 adb_out, adb_err)
587 if rc != 0:
588 self._adb_failure(adb_command, 'exited with %d' % rc, adb_out,
589 adb_err)
590 return output
591
525 def run_built_executable(self, name, *args, **kw): 592 def run_built_executable(self, name, *args, **kw):
526 """ 593 """
527 Runs an executable program built from a gyp-generated configuration. 594 Runs an executable program built from a gyp-generated configuration.
595 """
596 match = kw.pop('match', self.match)
528 597
529 This is not correctly implemented for Android. For now, we simply check 598 executable_file = self.built_file_path(name, type=self.EXECUTABLE, **kw)
530 that the executable file exists. 599 if executable_file not in self._to_install:
531 """ 600 self.fail_test()
532 # Running executables requires a device. Even if we build for target x86,
533 # the binary is not built with the correct toolchain options to actually
534 # run on the host.
535 601
536 # Copied from TestCommon.run() 602 if not self._device_serial:
537 match = kw.pop('match', self.match) 603 self.skip_test(message='No devices attached.\n')
538 status = None 604
539 if os.path.exists(self.built_file_path(name)): 605 storage = self._call_adb(['shell', 'echo', '$ANDROID_DATA']).strip()
540 status = 1 606 if not len(storage):
541 self._complete(None, None, None, None, status, match) 607 self.fail_test()
608
609 installed = set()
610 try:
611 for i in self._to_install:
612 a = os.path.abspath(
613 os.path.join(os.environ['ANDROID_BUILD_TOP'], i))
614 dest = '%s/%s' % (storage, os.path.basename(a))
615 self._call_adb(['push', os.path.abspath(a), dest])
616 installed.add(dest)
617 if i == executable_file:
618 device_executable = dest
619 self._call_adb(['shell', 'chmod', '755', device_executable])
620
621 out = self._call_adb(
622 ['shell', 'LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s' % storage,
623 device_executable])
624 out = out.replace('\r\n', '\n')
625 self._complete(out, kw.pop('stdout', None), None, None, None, match)
626 finally:
627 if len(installed):
628 self._call_adb(['shell', 'rm'] + list(installed))
542 629
543 def match_single_line(self, lines = None, expected_line = None): 630 def match_single_line(self, lines = None, expected_line = None):
544 """ 631 """
545 Checks that specified line appears in the text. 632 Checks that specified line appears in the text.
546 """ 633 """
547 for line in lines.split('\n'): 634 for line in lines.split('\n'):
548 if line == expected_line: 635 if line == expected_line:
549 return 1 636 return 1
550 return 637 return
551 638
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
1223 1310
1224 def TestGyp(*args, **kw): 1311 def TestGyp(*args, **kw):
1225 """ 1312 """
1226 Returns an appropriate TestGyp* instance for a specified GYP format. 1313 Returns an appropriate TestGyp* instance for a specified GYP format.
1227 """ 1314 """
1228 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) 1315 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
1229 for format_class in format_class_list: 1316 for format_class in format_class_list:
1230 if format == format_class.format: 1317 if format == format_class.format:
1231 return format_class(*args, **kw) 1318 return format_class(*args, **kw)
1232 raise Exception, "unknown format %r" % format 1319 raise Exception, "unknown format %r" % format
OLDNEW
« no previous file with comments | « test/configurations/inheritance/gyptest-inheritance.py ('k') | test/library/gyptest-shared.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698