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

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_PREFIX = 'Install: '
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 if l.startswith(TestGypAndroid._INSTALLABLE_PREFIX):
493 self._to_install.append(os.path.abspath(os.path.join(
494 os.environ['ANDROID_BUILD_TOP'],
495 l[len(TestGypAndroid._INSTALLABLE_PREFIX):])))
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
489 def intermediates_dir(self, group, module_name): 506 def intermediates_dir(self, group, module_name):
490 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group, 507 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group,
491 '%s_intermediates' % module_name) 508 '%s_intermediates' % module_name)
492 509
493 def built_file_path(self, name, type=None, **kw): 510 def built_file_path(self, name, type=None, **kw):
494 """ 511 """
495 Returns a path to the specified file name, of the specified type, 512 Returns a path to the specified file name, of the specified type,
496 as built by Android. Note that we don't support the configuration 513 as built by Android. Note that we don't support the configuration
497 parameter. 514 parameter.
498 """ 515 """
499 # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from 516 # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from
500 # the Android build system. 517 # the Android build system.
501 if type == None: 518 if type == None or type == self.EXECUTABLE:
502 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP', 519 return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP',
503 'shared_intermediates', name) 520 'shared_intermediates', name)
504 subdir = kw.get('subdir') 521 subdir = kw.get('subdir')
505 if type == self.EXECUTABLE:
506 # We don't install executables
507 group = 'EXECUTABLES'
508 module_name = self.android_module(group, name, subdir)
509 return os.path.join(self.intermediates_dir(group, module_name), name)
510 if type == self.STATIC_LIB: 522 if type == self.STATIC_LIB:
511 group = 'STATIC_LIBRARIES' 523 group = 'STATIC_LIBRARIES'
512 module_name = self.android_module(group, name, subdir) 524 module_name = self.android_module(group, name, subdir)
513 return os.path.join(self.intermediates_dir(group, module_name), 525 return os.path.join(self.intermediates_dir(group, module_name),
514 '%s.a' % module_name) 526 '%s.a' % module_name)
515 if type == self.SHARED_LIB: 527 if type == self.SHARED_LIB:
516 group = 'SHARED_LIBRARIES' 528 group = 'SHARED_LIBRARIES'
517 module_name = self.android_module(group, name, subdir) 529 module_name = self.android_module(group, name, subdir)
518 return os.path.join(self.intermediates_dir(group, module_name), 'LINKED', 530 return os.path.join(self.intermediates_dir(group, module_name), 'LINKED',
519 '%s.so' % module_name) 531 '%s.so' % module_name)
520 assert False, 'Unhandled type' 532 assert False, 'Unhandled type'
521 533
534 def _call_adb(self, command):
535 """ Calls the provided adb command.
536
537 If the command fails, the test fails.
538
539 Args:
540 command: The adb command to call.
541 Returns:
542 The command's output.
543 """
544 with tempfile.TemporaryFile(bufsize=0) as adb_out:
545 with tempfile.TemporaryFile(bufsize=0) as adb_err:
546 adb_command = [self._adb_path]
547 if self._device_serial:
548 adb_command += ['-s', self._device_serial]
549 adb_command += command
550 if subprocess.call(adb_command, stdout=adb_out, stderr=adb_err) != 0:
551 print '%s failed:' % ' '.join(adb_command)
552 print self.banner('STDOUT ')
553 adb_out.seek(0)
554 print adb_out.read()
555 print self.banner('STDERR ')
556 adb_err.seek(0)
557 print adb_err.read()
558 self.fail_test()
559 else:
560 adb_out.seek(0)
561 output = adb_out.read()
562 return output
563
522 def run_built_executable(self, name, *args, **kw): 564 def run_built_executable(self, name, *args, **kw):
523 """ 565 """
524 Runs an executable program built from a gyp-generated configuration. 566 Runs an executable program built from a gyp-generated configuration.
567 """
568 match = kw.pop('match', self.match)
525 569
526 This is not correctly implemented for Android. For now, we simply check 570 executable_file = self.built_file_path(name, type=self.EXECUTABLE, **kw)
527 that the executable file exists. 571 if executable_file not in self._to_install:
528 """ 572 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 573
533 # Copied from TestCommon.run() 574 if not self._device_serial:
534 match = kw.pop('match', self.match) 575 self.skip_test(message='No devices attached.\n')
535 status = None 576
536 if os.path.exists(self.built_file_path(name)): 577 storage = self._call_adb(['shell', 'echo', '$ANDROID_DATA']).strip()
537 status = 1 578 if not len(storage):
538 self._complete(None, None, None, None, status, match) 579 self.fail_test()
580
581 installed = []
582 try:
583 for i in self._to_install:
584 a = os.path.abspath(
585 os.path.join(os.environ['ANDROID_BUILD_TOP'], i))
586 dest = '%s/%s' % (storage, os.path.basename(a))
587 self._call_adb(['push', os.path.abspath(a), dest])
588 installed.append(dest)
589 if i == executable_file:
590 device_executable = dest
591 self._call_adb(['shell', 'chmod', '755', device_executable])
592
593 out = self._call_adb(
594 ['shell', 'LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s' % storage,
595 device_executable])
596 out = out.replace('\r\n', '\n')
597 self._complete(out, kw.pop('stdout', None), None, None, None, match)
598 finally:
599 if len(installed):
600 self._call_adb(['shell', 'rm'] + installed)
539 601
540 def match_single_line(self, lines = None, expected_line = None): 602 def match_single_line(self, lines = None, expected_line = None):
541 """ 603 """
542 Checks that specified line appears in the text. 604 Checks that specified line appears in the text.
543 """ 605 """
544 for line in lines.split('\n'): 606 for line in lines.split('\n'):
545 if line == expected_line: 607 if line == expected_line:
546 return 1 608 return 1
547 return 609 return
548 610
(...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 1282
1221 def TestGyp(*args, **kw): 1283 def TestGyp(*args, **kw):
1222 """ 1284 """
1223 Returns an appropriate TestGyp* instance for a specified GYP format. 1285 Returns an appropriate TestGyp* instance for a specified GYP format.
1224 """ 1286 """
1225 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT')) 1287 format = kw.pop('format', os.environ.get('TESTGYP_FORMAT'))
1226 for format_class in format_class_list: 1288 for format_class in format_class_list:
1227 if format == format_class.format: 1289 if format == format_class.format:
1228 return format_class(*args, **kw) 1290 return format_class(*args, **kw)
1229 raise Exception, "unknown format %r" % format 1291 raise Exception, "unknown format %r" % format
OLDNEW
« pylib/gyp/generator/android.py ('K') | « pylib/gyp/generator/android.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698