blob: bdf3751e617253b4b7ba8f5cf5aa285a35596417 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import optimize_webui
import os
import shutil
import tempfile
import unittest
_CWD = os.getcwd()
_HERE_DIR = os.path.dirname(__file__)
class OptimizeWebUiTest(unittest.TestCase):
def setUp(self):
self._tmp_dirs = []
self._tmp_src_dir = None
self._out_folder = self._create_tmp_dir()
def tearDown(self):
for tmp_dir in self._tmp_dirs:
shutil.rmtree(tmp_dir)
def _write_file_to_dir(self, file_path, file_contents):
file_dir = os.path.dirname(file_path)
if not os.path.exists(file_dir):
os.makedirs(file_dir)
with open(file_path, 'w') as tmp_file:
tmp_file.write(file_contents)
def _write_file_to_src_dir(self, file_path, file_contents):
if not self._tmp_src_dir:
self._tmp_src_dir = self._create_tmp_dir()
file_path_normalized = os.path.normpath(
os.path.join(self._tmp_src_dir, file_path))
self._write_file_to_dir(file_path_normalized, file_contents)
def _create_tmp_dir(self):
# TODO(dbeam): support cross-drive paths (i.e. d:\ vs c:\).
tmp_dir = tempfile.mkdtemp(dir=_HERE_DIR)
self._tmp_dirs.append(tmp_dir)
return tmp_dir
def _read_out_file(self, file_name):
assert self._out_folder
with open(os.path.join(self._out_folder, file_name), 'r') as f:
return f.read()
def _run_optimize(self, input_args):
# TODO(dbeam): make it possible to _run_optimize twice? Is that useful?
args = input_args + [
'--depfile',
os.path.join(self._out_folder, 'depfile.d'),
'--target_name',
'dummy_target_name',
'--input',
self._tmp_src_dir,
'--out_folder',
self._out_folder,
]
optimize_webui.main(args)
def _write_v3_files_to_src_dir(self):
self._write_file_to_src_dir('element.js', "alert('yay');")
self._write_file_to_src_dir('element_in_dir/element_in_dir.js',
"alert('hello from element_in_dir');")
self._write_file_to_src_dir(
'ui.js', '''
import './element.js';
import './element_in_dir/element_in_dir.js';
''')
self._write_file_to_src_dir(
'ui.html', '''
<script type="module" src="ui.js"></script>
''')
def _write_v3_files_with_custom_path_to_src_dir(self, custom_path):
self._write_file_to_dir(
os.path.join(custom_path, 'external_dir', 'external_element.js'), '''
import './sub_dir/external_element_dep.js';
alert('hello from external_element');
''')
self._write_file_to_dir(
os.path.join(custom_path, 'external_dir', 'sub_dir',
'external_element_dep.js'),
"alert('hello from external_element_dep');")
self._write_file_to_src_dir('element.js', "alert('yay');")
self._write_file_to_src_dir(
'ui.js', '''
import './element.js';
import 'some-fake-scheme://foo/external_dir/external_element.js';
''')
self._write_file_to_src_dir(
'ui.html', '''
<script type="module" src="ui.js"></script>
''')
def _write_v3_files_with_resources_to_src_dir(self, resources_scheme):
resources_path = os.path.join(
_HERE_DIR.replace('\\', '/'), 'gen', 'ui', 'webui', 'resources',
'preprocessed', 'js')
fake_resource_path = os.path.join(resources_path, 'fake_resource.js')
scheme_relative_resource_path = os.path.join(resources_path,
'scheme_relative_resource.js')
os.makedirs(os.path.dirname(resources_path))
self._tmp_dirs.append('gen')
self._write_file_to_dir(
fake_resource_path, '''
export const foo = 5;
alert('hello from shared resource');''')
self._write_file_to_dir(
scheme_relative_resource_path, '''
export const bar = 6;
alert('hello from another shared resource');''')
self._write_file_to_src_dir(
'element.js', '''
import '%s//resources/js/fake_resource.js';
import {bar} from '//resources/js/scheme_relative_resource.js';
alert('yay ' + bar);
''' % resources_scheme)
self._write_file_to_src_dir(
'element_in_dir/element_in_dir.js', '''
import {foo} from '%s//resources/js/fake_resource.js';
import '../strings.m.js';
alert('hello from element_in_dir ' + foo);
''' % resources_scheme)
self._write_file_to_src_dir(
'ui.js', '''
import './strings.m.js';
import './element.js';
import './element_in_dir/element_in_dir.js';
''')
self._write_file_to_src_dir(
'ui.html', '''
<script type="module" src="ui.js"></script>
''')
def _check_output_html(self, out_html):
self.assertNotIn('element.html', out_html)
self.assertNotIn('element.js', out_html)
self.assertNotIn('element_in_dir.html', out_html)
self.assertNotIn('element_in_dir.js', out_html)
self.assertIn('got here!', out_html)
def _check_output_js(self, output_js_name):
output_js = self._read_out_file(output_js_name)
self.assertIn('yay', output_js)
self.assertIn('hello from element_in_dir', output_js)
def _check_output_depfile(self, has_html):
depfile_d = self._read_out_file('depfile.d')
self.assertIn('element.js', depfile_d)
self.assertIn(
os.path.normpath('element_in_dir/element_in_dir.js'), depfile_d)
if (has_html):
self.assertIn('element.html', depfile_d)
self.assertIn(
os.path.normpath('element_in_dir/element_in_dir.html'), depfile_d)
def testV3SimpleOptimize(self):
self._write_v3_files_to_src_dir()
args = [
'--host',
'fake-host',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
]
self._run_optimize(args)
self._check_output_js('ui.rollup.js')
self._check_output_depfile(False)
def testV3OptimizeWithResources(self):
self._write_v3_files_with_resources_to_src_dir('chrome:')
resources_path = os.path.join('gen', 'ui', 'webui', 'resources',
'preprocessed')
args = [
'--host',
'fake-host',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
'--external_paths',
'chrome://resources|%s' % resources_path,
]
self._run_optimize(args)
ui_rollup_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', ui_rollup_js)
self.assertIn('hello from element_in_dir', ui_rollup_js)
self.assertIn('hello from shared resource', ui_rollup_js)
depfile_d = self._read_out_file('depfile.d')
self.assertIn('element.js', depfile_d)
self.assertIn(
os.path.normpath('element_in_dir/element_in_dir.js'), depfile_d)
self.assertIn(
os.path.normpath(
'../gen/ui/webui/resources/preprocessed/js/scheme_relative_resource.js'
), depfile_d)
self.assertIn(
os.path.normpath(
'../gen/ui/webui/resources/preprocessed/js/fake_resource.js'),
depfile_d)
def testV3MultiBundleOptimize(self):
self._write_v3_files_to_src_dir()
self._write_file_to_src_dir('lazy_element.js',
"alert('hello from lazy_element');")
self._write_file_to_src_dir(
'lazy.js', '''
import './lazy_element.js';
import './element_in_dir/element_in_dir.js';
''')
args = [
'--host',
'fake-host',
'--js_module_in_files',
'ui.js',
'lazy.js',
'--js_out_files',
'ui.rollup.js',
'lazy.rollup.js',
'shared.rollup.js',
'--out-manifest',
os.path.join(self._out_folder, 'out_manifest.json'),
]
self._run_optimize(args)
# Check that the shared element is in the shared bundle and the non-shared
# elements are in the individual bundles.
ui_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', ui_js)
self.assertNotIn('hello from lazy_element', ui_js)
self.assertNotIn('hello from element_in_dir', ui_js)
lazy_js = self._read_out_file('lazy.rollup.js')
self.assertNotIn('yay', lazy_js)
self.assertIn('hello from lazy_element', lazy_js)
self.assertNotIn('hello from element_in_dir', lazy_js)
shared_js = self._read_out_file('shared.rollup.js')
self.assertNotIn('yay', shared_js)
self.assertNotIn('hello from lazy_element', shared_js)
self.assertIn('hello from element_in_dir', shared_js)
# All 3 JS files should be in the depfile.
self._check_output_depfile(False)
depfile_d = self._read_out_file('depfile.d')
self.assertIn('lazy_element.js', depfile_d)
manifest = json.loads(self._read_out_file('out_manifest.json'))
self.assertEqual(3, len(manifest['files']))
self.assertTrue('lazy.rollup.js' in manifest['files'])
self.assertTrue('ui.rollup.js' in manifest['files'])
self.assertTrue('shared.rollup.js' in manifest['files'])
self.assertEqual(
os.path.relpath(self._out_folder, _CWD).replace('\\', '/'),
os.path.relpath(manifest['base_dir'], _CWD).replace('\\', '/'))
def testV3OptimizeWithCustomPaths(self):
custom_dir = os.path.join(self._create_tmp_dir(), 'foo_root')
self._write_v3_files_with_custom_path_to_src_dir(custom_dir)
resources_path = os.path.join('gen', 'ui', 'webui', 'resources',
'preprocessed')
args = [
'--host',
'fake-host',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
'--external_paths',
'chrome://resources|%s' % resources_path,
'some-fake-scheme://foo|%s' % os.path.abspath(custom_dir),
]
self._run_optimize(args)
ui_rollup_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', ui_rollup_js)
self.assertIn('hello from external_element', ui_rollup_js)
self.assertIn('hello from external_element_dep', ui_rollup_js)
depfile_d = self._read_out_file('depfile.d')
self.assertIn('element.js', depfile_d)
# Relative path from the src of the root module to the external root dir
relpath = os.path.relpath(custom_dir, self._tmp_src_dir)
self.assertIn(
os.path.normpath(
os.path.join(relpath, 'external_dir', 'external_element.js')),
depfile_d)
self.assertIn(
os.path.normpath(
os.path.join(relpath, 'external_dir', 'sub_dir',
'external_element_dep.js')), depfile_d)
def testV3SimpleOptimizeExcludes(self):
self._write_v3_files_to_src_dir()
args = [
'--host',
'chrome-extension://myextensionid/',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
'--exclude',
'element_in_dir/element_in_dir.js',
]
self._run_optimize(args)
output_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', output_js)
self.assertNotIn('hello from element_in_dir', output_js)
depfile_d = self._read_out_file('depfile.d')
self.assertIn('element.js', depfile_d)
self.assertNotIn('element_in_dir', depfile_d)
# Tests that bundling resources for an untrusted UI can successfully exclude
# resources imported from both chrome-untrusted://resources and scheme
# relative paths.
def testV3SimpleOptimizeExcludesResources(self):
self._write_v3_files_with_resources_to_src_dir('chrome-untrusted:')
resources_path = os.path.join('gen', 'ui', 'webui', 'resources',
'preprocessed')
args = [
'--host',
'chrome-untrusted://fake-host',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
'--external_paths',
'//resources|%s' % resources_path,
'chrome-untrusted://resources|%s' % resources_path,
'--exclude',
'//resources/js/scheme_relative_resource.js',
'chrome-untrusted://resources/js/fake_resource.js',
]
self._run_optimize(args)
output_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', output_js)
self.assertIn('//resources/js/scheme_relative_resource.js', output_js)
self.assertIn('chrome-untrusted://resources/js/fake_resource.js', output_js)
self.assertNotIn('hello from another shared resource', output_js)
self.assertNotIn('hello from shared resource', output_js)
depfile_d = self._read_out_file('depfile.d')
self.assertNotIn('fake_resource', depfile_d)
self.assertNotIn('scheme_relative_resource', depfile_d)
# Tests that bundling resources for an untrusted UI successfully bundles
# resources from both chrome-untrusted://resources and //resources.
def testV3SimpleOptimizeUntrustedResources(self):
self._write_v3_files_with_resources_to_src_dir('chrome-untrusted:')
resources_path = os.path.join('gen', 'ui', 'webui', 'resources',
'preprocessed')
args = [
'--host',
'chrome-untrusted://fake-host',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
'--external_paths',
'//resources|%s' % resources_path,
'chrome-untrusted://resources|%s' % resources_path,
]
self._run_optimize(args)
output_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', output_js)
self.assertIn('hello from another shared resource', output_js)
self.assertIn('hello from shared resource', output_js)
depfile_d = self._read_out_file('depfile.d')
self.assertIn('fake_resource', depfile_d)
self.assertIn('scheme_relative_resource', depfile_d)
def testV3OptimizeWithCustomLayeredPaths(self):
tmp_dir = self._create_tmp_dir()
custom_dir_foo = os.path.join(tmp_dir, 'foo_root')
custom_dir_bar = os.path.join(tmp_dir, 'bar_root')
self._write_v3_files_with_custom_path_to_src_dir(custom_dir_foo)
# Overwrite one of the foo files to import something from
# some-fake-scheme://bar.
self._write_file_to_dir(
os.path.join(custom_dir_foo, 'external_dir', 'sub_dir',
'external_element_dep.js'), '''
import 'some-fake-scheme://bar/another_element.js';
alert('hello from external_element_dep');''')
# Write that file to the bar_root directory.
self._write_file_to_dir(
os.path.join(custom_dir_bar, 'another_element.js'),
"alert('hello from another external dep');")
resources_path = os.path.join('gen', 'ui', 'webui', 'resources',
'preprocessed')
args = [
'--host',
'fake-host',
'--js_module_in_files',
'ui.js',
'--js_out_files',
'ui.rollup.js',
'--external_paths',
'//resources|%s' % resources_path,
'some-fake-scheme://foo|%s' % os.path.abspath(custom_dir_foo),
'some-fake-scheme://bar|%s' % os.path.abspath(custom_dir_bar),
]
self._run_optimize(args)
ui_rollup_js = self._read_out_file('ui.rollup.js')
self.assertIn('yay', ui_rollup_js)
self.assertIn('hello from external_element', ui_rollup_js)
self.assertIn('hello from external_element_dep', ui_rollup_js)
self.assertIn('hello from another external dep', ui_rollup_js)
depfile_d = self._read_out_file('depfile.d')
self.assertIn('element.js', depfile_d)
# Relative path from the src of the root module to the external root dir
relpath = os.path.relpath(custom_dir_foo, self._tmp_src_dir)
self.assertIn(
os.path.normpath(
os.path.join(relpath, 'external_dir', 'external_element.js')),
depfile_d)
self.assertIn(
os.path.normpath(
os.path.join(relpath, 'external_dir', 'sub_dir',
'external_element_dep.js')), depfile_d)
# Relative path from the src of the root module to the secondary dependency
# root dir.
relpath_bar = os.path.relpath(custom_dir_bar, self._tmp_src_dir)
self.assertIn(
os.path.normpath(os.path.join(relpath_bar, 'another_element.js')),
depfile_d)
if __name__ == '__main__':
unittest.main()