• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3# Copyright (c) 2012 Google Inc. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""
8Verifies that device and simulator bundles are built correctly.
9"""
10
11import plistlib
12import TestGyp
13import os
14import struct
15import subprocess
16import sys
17import tempfile
18
19
20def CheckFileType(file, expected):
21  proc = subprocess.Popen(['lipo', '-info', file], stdout=subprocess.PIPE)
22  o = proc.communicate()[0].strip()
23  assert not proc.returncode
24  if not expected in o:
25    print 'File: Expected %s, got %s' % (expected, o)
26    test.fail_test()
27
28def HasCerts():
29  # Because the bots do not have certs, don't check them if there are no
30  # certs available.
31  proc = subprocess.Popen(['security','find-identity','-p', 'codesigning',
32                           '-v'], stdout=subprocess.PIPE)
33  return "0 valid identities found" not in proc.communicate()[0].strip()
34
35def CheckSignature(file):
36  proc = subprocess.Popen(['codesign', '-v', file], stdout=subprocess.PIPE)
37  o = proc.communicate()[0].strip()
38  assert not proc.returncode
39  if "code object is not signed at all" in o:
40    print 'File %s not properly signed.' % (file)
41    test.fail_test()
42
43def CheckEntitlements(file, expected_entitlements):
44  with tempfile.NamedTemporaryFile() as temp:
45    proc = subprocess.Popen(['codesign', '--display', '--entitlements',
46                             temp.name, file], stdout=subprocess.PIPE)
47    o = proc.communicate()[0].strip()
48    assert not proc.returncode
49    data = temp.read()
50  entitlements = ParseEntitlements(data)
51  if not entitlements:
52    print 'No valid entitlements found in %s.' % (file)
53    test.fail_test()
54  if entitlements != expected_entitlements:
55    print 'Unexpected entitlements found in %s.' % (file)
56    test.fail_test()
57
58def ParseEntitlements(data):
59  if len(data) < 8:
60    return None
61  magic, length = struct.unpack('>II', data[:8])
62  if magic != 0xfade7171 or length != len(data):
63    return None
64  return data[8:]
65
66def GetProductVersion():
67  args = ['xcodebuild','-version','-sdk','iphoneos','ProductVersion']
68  job = subprocess.Popen(args, stdout=subprocess.PIPE)
69  return job.communicate()[0].strip()
70
71def CheckPlistvalue(plist, key, expected):
72  if key not in plist:
73    print '%s not set in plist' % key
74    test.fail_test()
75    return
76  actual = plist[key]
77  if actual != expected:
78    print 'File: Expected %s, got %s for %s' % (expected, actual, key)
79    test.fail_test()
80
81def CheckPlistNotSet(plist, key):
82  if key in plist:
83    print '%s should not be set in plist' % key
84    test.fail_test()
85    return
86
87def ConvertBinaryPlistToXML(path):
88  proc = subprocess.call(['plutil', '-convert', 'xml1', path],
89                         stdout=subprocess.PIPE)
90
91if sys.platform == 'darwin':
92  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
93
94  test.run_gyp('test-device.gyp', chdir='app-bundle')
95
96  test_configs = ['Default-iphoneos', 'Default']
97  # TODO(justincohen): Disabling 'Default-iphoneos' for xcode until bots are
98  # configured with signing certs.
99  if test.format == 'xcode':
100    test_configs.remove('Default-iphoneos')
101
102  for configuration in test_configs:
103    test.set_configuration(configuration)
104    test.build('test-device.gyp', 'test_app', chdir='app-bundle')
105    result_file = test.built_file_path('Test App Gyp.bundle/Test App Gyp',
106                                       chdir='app-bundle')
107    test.must_exist(result_file)
108
109    info_plist = test.built_file_path('Test App Gyp.bundle/Info.plist',
110                                      chdir='app-bundle')
111
112    # plistlib doesn't support binary plists, but that's what Xcode creates.
113    if test.format == 'xcode':
114      ConvertBinaryPlistToXML(info_plist)
115    plist = plistlib.readPlist(info_plist)
116
117    CheckPlistvalue(plist, 'UIDeviceFamily', [1, 2])
118
119    if configuration == 'Default-iphoneos':
120      CheckFileType(result_file, 'armv7')
121      CheckPlistvalue(plist, 'DTPlatformVersion', GetProductVersion())
122      CheckPlistvalue(plist, 'CFBundleSupportedPlatforms', ['iPhoneOS'])
123      CheckPlistvalue(plist, 'DTPlatformName', 'iphoneos')
124    else:
125      CheckFileType(result_file, 'i386')
126      CheckPlistNotSet(plist, 'DTPlatformVersion')
127      CheckPlistvalue(plist, 'CFBundleSupportedPlatforms', ['iPhoneSimulator'])
128      CheckPlistvalue(plist, 'DTPlatformName', 'iphonesimulator')
129
130    if HasCerts() and configuration == 'Default-iphoneos':
131      test.build('test-device.gyp', 'sig_test', chdir='app-bundle')
132      result_file = test.built_file_path('sig_test.bundle/sig_test',
133                                         chdir='app-bundle')
134      CheckSignature(result_file)
135      info_plist = test.built_file_path('sig_test.bundle/Info.plist',
136                                        chdir='app-bundle')
137
138      plist = plistlib.readPlist(info_plist)
139      CheckPlistvalue(plist, 'UIDeviceFamily', [1])
140
141      entitlements_file = test.built_file_path('sig_test.xcent',
142                                               chdir='app-bundle')
143      if os.path.isfile(entitlements_file):
144        expected_entitlements = open(entitlements_file).read()
145        CheckEntitlements(result_file, expected_entitlements)
146
147  test.pass_test()
148