1#!/usr/bin/env python
2# Copyright 2013 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import json
7import unittest
8
9from extensions_paths import CHROME_EXTENSIONS
10from server_instance import ServerInstance
11from test_file_system import TestFileSystem
12
13
14_TEST_FILESYSTEM = {
15  'api': {
16    '_api_features.json': json.dumps({
17      'audioCapture': {
18        'channel': 'stable',
19        'extension_types': ['platform_app']
20      },
21      'background': [
22        {
23          'channel': 'stable',
24          'extension_types': ['extension']
25        },
26        {
27          'channel': 'stable',
28          'extension_types': ['platform_app'],
29          'whitelist': ['im not here']
30        }
31      ],
32      'inheritsFromDifferentDependencyName': {
33        'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency']
34      },
35      'inheritsPlatformAndChannelFromDependency': {
36        'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency']
37      },
38      'omnibox': {
39        'dependencies': ['manifest:omnibox'],
40        'contexts': ['blessed_extension']
41      },
42      'syncFileSystem': {
43        'dependencies': ['permission:syncFileSystem'],
44        'contexts': ['blessed_extension']
45      },
46      'tabs': {
47        'channel': 'stable',
48        'extension_types': ['extension', 'legacy_packaged_app'],
49        'contexts': ['blessed_extension']
50      },
51      'test': {
52        'channel': 'stable',
53        'extension_types': 'all',
54        'contexts': [
55            'blessed_extension', 'unblessed_extension', 'content_script']
56      },
57      'overridesPlatformAndChannelFromDependency': {
58        'channel': 'beta',
59        'dependencies': [
60          'permission:overridesPlatformAndChannelFromDependency'
61        ],
62        'extension_types': ['platform_app']
63      },
64      'windows': {
65        'dependencies': ['api:tabs'],
66        'contexts': ['blessed_extension']
67      },
68      'testDeep1': {
69        'dependencies': ['api:testDeep2']
70      },
71      'testDeep2': {
72        'dependencies': ['api:testDeep3']
73      },
74      'testDeep3': {
75        'dependencies': ['manifest:testDeep4']
76      },
77      'testDeep1.child': {},
78      'multipleAmbiguous': [{
79        'value': 1,
80        'extension_types': ['platform_app']
81      }, {
82        'value': 2,
83        'dependencies': ['manifest:multipleAmbiguous']
84      }],
85      'mergingDependencies1': {
86        'dependencies': [
87          'permission:mergingDependencies1',
88          'permission:mergingDependencies2'
89        ]
90      },
91      'mergingDependencies2': {
92        'dependencies': [
93          'permission:mergingDependencies1',
94          'permission:mergingDependencies3'
95        ]
96      },
97      'mergingDependencies3': {
98        'dependencies': [
99          'permission:mergingDependencies2',
100          'permission:mergingDependencies3'
101        ]
102      },
103      'implicitNoParent.child': {
104        'extension_types': ['extension'],
105        'channel': 'stable'
106      },
107      'parent': {
108        'extension_types': ['extension'],
109        'channel': 'beta'
110      },
111      'parent.explicitNoParent': {
112        'extension_types': ['extension'],
113        'noparent': True
114      },
115      'parent.inheritAndOverride': {
116        'channel': 'dev'
117      },
118      'overridePlatform': {
119        'dependencies': ['permission:tabs'],
120        'extension_types': 'platform_app'
121      },
122      'mergeMostStableChannel': [{
123        'channel': 'dev',
124        'extension_types': ['extension'],
125        'value1': 1
126      }, {
127        'channel': 'stable',
128        'extension_types': ['extension'],
129        'value2': 2
130      }, {
131        'channel': 'beta',
132        'extension_types': ['extension'],
133        'value3': 3
134      }, {
135        'channel': 'stable',
136        'extension_types': ['extension'],
137        'value4': 4
138      }, {
139        'extension_types': ['extension'],
140        'value5': 5
141      }]
142    }),
143    '_manifest_features.json': json.dumps({
144      'app.content_security_policy': {
145        'channel': 'stable',
146        'extension_types': ['platform_app'],
147        'min_manifest_version': 2,
148        'whitelist': ['this isnt happening']
149      },
150      'background': {
151        'channel': 'stable',
152        'extension_types': ['extension', 'legacy_packaged_app', 'hosted_app']
153      },
154      'inheritsPlatformAndChannelFromDependency': {
155        'channel': 'dev',
156        'extension_types': ['extension']
157      },
158      'manifest_version': {
159        'channel': 'stable',
160        'extension_types': 'all'
161      },
162      'omnibox': {
163        'channel': 'stable',
164        'extension_types': ['extension'],
165        'platforms': ['win']
166      },
167      'page_action': {
168        'channel': 'stable',
169        'extension_types': ['extension']
170      },
171      'sockets': {
172        'channel': 'dev',
173        'extension_types': ['platform_app']
174      },
175      'testDeep4': {
176        'extension_types': ['extension']
177      },
178      'multipleAmbiguous': {
179        'extension_types': ['extension']
180      }
181    }),
182    '_permission_features.json': json.dumps({
183      'bluetooth': {
184        'channel': 'dev',
185        'extension_types': ['platform_app']
186      },
187      'overridesPlatformAndChannelFromDependency': {
188        'channel': 'stable',
189        'extension_types': ['extension']
190      },
191      'power': {
192        'channel': 'stable',
193        'extension_types': [
194          'extension', 'legacy_packaged_app', 'platform_app'
195        ]
196      },
197      'syncFileSystem': {
198        'channel': 'stable',
199        'extension_types': ['platform_app']
200      },
201      'tabs': {
202        'channel': 'stable',
203        'extension_types': ['extension']
204      },
205      'mergingDependencies1': {
206        'channel': 'stable',
207        'extension_types': 'all'
208      },
209      'mergingDependencies2': {
210        'channel': 'beta',
211        'extension_types': ['platform_app']
212      },
213      'mergingDependencies3': {
214        'extension_types': ['extension']
215      },
216      'defaults': {}
217    })
218  },
219  'docs': {
220    'templates': {
221      'json': {
222        'manifest.json': json.dumps({
223          'background': {
224            'documentation': 'background_pages.html'
225          },
226          'manifest_version': {
227            'documentation': 'manifest/manifest_version.html',
228            'example': 2,
229            'level': 'required'
230          },
231          'page_action': {
232            'documentation': 'pageAction.html',
233            'example': {},
234            'level': 'only_one'
235          }
236        }),
237        'permissions.json': json.dumps({
238          'fakeUnsupportedFeature': {},
239          'syncFileSystem': {
240            'partial': 'permissions/sync_file_system.html'
241          },
242          'tabs': {
243            'partial': 'permissions/tabs.html'
244          }
245        })
246      }
247    }
248  }
249}
250
251
252class FeaturesBundleTest(unittest.TestCase):
253  def setUp(self):
254    self._server = ServerInstance.ForTest(
255        TestFileSystem(_TEST_FILESYSTEM, relative_to=CHROME_EXTENSIONS))
256
257  def testManifestFeatures(self):
258    expected_features = {
259      'background': {
260        'name': 'background',
261        'channel': 'stable',
262        'documentation': 'background_pages.html',
263        'extension_types': ['extension', 'legacy_packaged_app', 'hosted_app']
264      },
265      'inheritsPlatformAndChannelFromDependency': {
266        'name': 'inheritsPlatformAndChannelFromDependency',
267        'channel': 'dev',
268        'extension_types': ['extension']
269      },
270      'manifest_version': {
271        'name': 'manifest_version',
272        'channel': 'stable',
273        'documentation': 'manifest/manifest_version.html',
274        'extension_types': 'all',
275        'level': 'required',
276        'example': 2,
277      },
278      'omnibox': {
279        'name': 'omnibox',
280        'channel': 'stable',
281        'extension_types': ['extension'],
282        'platforms': ['win'],
283      },
284      'page_action': {
285        'name': 'page_action',
286        'channel': 'stable',
287        'documentation': 'pageAction.html',
288        'extension_types': ['extension'],
289        'level': 'only_one',
290        'example': {},
291      },
292      'testDeep4': {
293        'name': 'testDeep4',
294        'channel': 'stable',
295        'extension_types': ['extension']
296      },
297      'multipleAmbiguous': {
298        'name': 'multipleAmbiguous',
299        'channel': 'stable',
300        'extension_types': ['extension']
301      }
302    }
303    self.assertEqual(
304        expected_features,
305        self._server.platform_bundle.GetFeaturesBundle(
306            'extensions').GetManifestFeatures().Get())
307    expected_features = {
308      'manifest_version': {
309        'name': 'manifest_version',
310        'channel': 'stable',
311        'documentation': 'manifest/manifest_version.html',
312        'extension_types': 'all',
313        'level': 'required',
314        'example': 2,
315      },
316      'sockets': {
317        'name': 'sockets',
318        'channel': 'dev',
319        'extension_types': ['platform_app']
320      }
321    }
322    self.assertEqual(
323        expected_features,
324        self._server.platform_bundle.GetFeaturesBundle(
325            'apps').GetManifestFeatures().Get())
326
327  def testPermissionFeatures(self):
328    expected_features = {
329      'power': {
330        'name': 'power',
331        'channel': 'stable',
332        'extension_types': ['extension', 'legacy_packaged_app', 'platform_app']
333      },
334      'overridesPlatformAndChannelFromDependency': {
335        'name': 'overridesPlatformAndChannelFromDependency',
336        'channel': 'stable',
337        'extension_types': ['extension']
338      },
339      'tabs': {
340        'name': 'tabs',
341        'channel': 'stable',
342        'extension_types': ['extension'],
343        'partial': 'permissions/tabs.html'
344      },
345      'mergingDependencies1': {
346        'name': 'mergingDependencies1',
347        'channel': 'stable',
348        'extension_types': 'all'
349      },
350      'mergingDependencies3': {
351        'name': 'mergingDependencies3',
352        'channel': 'stable',
353        'extension_types': ['extension']
354      },
355      'defaults': {
356        'name': 'defaults',
357        'channel': 'stable'
358      }
359    }
360    self.assertEqual(
361        expected_features,
362        self._server.platform_bundle.GetFeaturesBundle(
363            'extensions').GetPermissionFeatures().Get())
364    expected_features = {
365      'bluetooth': {
366        'name': 'bluetooth',
367        'channel': 'dev',
368        'extension_types': ['platform_app']
369      },
370      'power': {
371        'name': 'power',
372        'channel': 'stable',
373        'extension_types': ['extension', 'legacy_packaged_app', 'platform_app']
374      },
375      'syncFileSystem': {
376        'name': 'syncFileSystem',
377        'channel': 'stable',
378        'extension_types': ['platform_app'],
379        'partial': 'permissions/sync_file_system.html'
380      },
381      'mergingDependencies1': {
382        'name': 'mergingDependencies1',
383        'channel': 'stable',
384        'extension_types': 'all'
385      },
386      'mergingDependencies2': {
387        'name': 'mergingDependencies2',
388        'channel': 'beta',
389        'extension_types': ['platform_app']
390      },
391      'defaults': {
392        'name': 'defaults',
393        'channel': 'stable'
394      }
395    }
396    self.assertEqual(
397        expected_features,
398        self._server.platform_bundle.GetFeaturesBundle(
399            'apps').GetPermissionFeatures().Get())
400
401  def testAPIFeatures(self):
402    expected_features = {
403      'background': {
404        'name': 'background',
405        'channel': 'stable',
406        'extension_types': ['extension']
407      },
408      'omnibox': {
409        'name': 'omnibox',
410        'contexts': ['blessed_extension'],
411        'dependencies': ['manifest:omnibox'],
412        'channel': 'stable'
413      },
414      'tabs': {
415        'name': 'tabs',
416        'channel': 'stable',
417        'contexts': ['blessed_extension'],
418        'extension_types': ['extension', 'legacy_packaged_app'],
419      },
420      'test': {
421        'name': 'test',
422        'channel': 'stable',
423        'contexts': [
424            'blessed_extension', 'unblessed_extension', 'content_script'],
425        'extension_types': 'all',
426      },
427      'windows': {
428        'name': 'windows',
429        'contexts': ['blessed_extension'],
430        'dependencies': ['api:tabs'],
431        'channel': 'stable'
432      },
433      'testDeep1': {
434        'name': 'testDeep1',
435        'dependencies': ['api:testDeep2'],
436        'channel': 'stable'
437      },
438      'testDeep2': {
439        'name': 'testDeep2',
440        'dependencies': ['api:testDeep3'],
441        'channel': 'stable'
442      },
443      'testDeep3': {
444        'name': 'testDeep3',
445        'dependencies': ['manifest:testDeep4'],
446        'channel': 'stable'
447      },
448      'testDeep1.child': {
449        'name': 'testDeep1.child',
450        'channel': 'stable',
451        'dependencies': ['api:testDeep2']
452      },
453      'multipleAmbiguous': {
454        'name': 'multipleAmbiguous',
455        'value': 2,
456        'dependencies': ['manifest:multipleAmbiguous'],
457        'channel': 'stable'
458      },
459      'mergingDependencies2': {
460        'name': 'mergingDependencies2',
461        'dependencies': [
462          'permission:mergingDependencies1',
463          'permission:mergingDependencies3'
464        ],
465        'channel': 'stable'
466      },
467      'inheritsFromDifferentDependencyName': {
468        'channel': 'dev',
469        'name': 'inheritsFromDifferentDependencyName',
470        'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency'],
471      },
472      'inheritsPlatformAndChannelFromDependency': {
473        'channel': 'dev',
474        'name': 'inheritsPlatformAndChannelFromDependency',
475        'dependencies': ['manifest:inheritsPlatformAndChannelFromDependency'],
476      },
477      'implicitNoParent.child': {
478        'name': 'implicitNoParent.child',
479        'channel': 'stable',
480        'extension_types': ['extension'],
481      },
482      'parent': {
483        'name': 'parent',
484        'channel': 'beta',
485        'extension_types': ['extension'],
486      },
487      'parent.explicitNoParent': {
488        'name': 'parent.explicitNoParent',
489        'channel': 'stable',
490        'extension_types': ['extension'],
491        'noparent': True
492      },
493      'parent.inheritAndOverride': {
494        'name': 'parent.inheritAndOverride',
495        'channel': 'dev',
496        'extension_types': ['extension']
497      },
498      'mergeMostStableChannel': {
499        'name': 'mergeMostStableChannel',
500        'channel': 'stable',
501        'extension_types': ['extension'],
502        'value2': 2,
503        'value4': 4,
504        'value5': 5
505      }
506    }
507    self.assertEqual(
508        expected_features,
509        self._server.platform_bundle.GetFeaturesBundle(
510            'extensions').GetAPIFeatures().Get())
511    expected_features = {
512      'audioCapture': {
513        'name': 'audioCapture',
514        'channel': 'stable',
515        'extension_types': ['platform_app']
516      },
517      'syncFileSystem': {
518        'name': 'syncFileSystem',
519        'contexts': ['blessed_extension'],
520        'dependencies': ['permission:syncFileSystem'],
521        'channel': 'stable'
522      },
523      'test': {
524        'name': 'test',
525        'channel': 'stable',
526        'contexts': [
527            'blessed_extension', 'unblessed_extension', 'content_script'],
528        'extension_types': 'all',
529      },
530      'multipleAmbiguous': {
531        'name': 'multipleAmbiguous',
532        'channel': 'stable',
533        'extension_types': ['platform_app'],
534        'value': 1,
535      },
536      'mergingDependencies1': {
537        'name': 'mergingDependencies1',
538        'channel': 'beta',
539        'dependencies': [
540          'permission:mergingDependencies1',
541          'permission:mergingDependencies2'
542        ],
543      },
544      'overridesPlatformAndChannelFromDependency': {
545        'name': 'overridesPlatformAndChannelFromDependency',
546        'channel': 'beta',
547        'dependencies': [
548          'permission:overridesPlatformAndChannelFromDependency'
549        ],
550        'extension_types': ['platform_app']
551      },
552      'overridePlatform': {
553        'name': 'overridePlatform',
554        'channel': 'stable',
555        'dependencies': ['permission:tabs'],
556        'extension_types': 'platform_app'
557      }
558    }
559    self.assertEqual(
560        expected_features,
561        self._server.platform_bundle.GetFeaturesBundle(
562            'apps').GetAPIFeatures().Get())
563
564
565if __name__ == '__main__':
566  unittest.main()
567