def test_yaml_valid_app_names(self, mock_loadPlugin): valid_app_names = [ '1', 'a', 'aa', 'aaa', 'aaaa', 'Aa', 'aA', '1a', 'a1', '1-a', 'a-1', 'a-a', 'aa-a', 'a-aa', 'a-b-c', '0a-a', 'a-0a', ] fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) for app_name in valid_app_names: with self.subTest(key=app_name): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: nothing confinement: strict apps: {!r}: command: foo parts: part1: plugin: nil """.format(app_name)) c = project_loader.Config() self.assertTrue(app_name in c.data['apps'])
def test_config_snap_environment_with_dependencies(self, mock_get_dependencies): library_paths = { os.path.join(self.snap_dir, 'lib1'), os.path.join(self.snap_dir, 'lib2'), } mock_get_dependencies.return_value = library_paths config = project_loader.Config() for lib_path in library_paths: os.makedirs(lib_path) # Ensure that LD_LIBRARY_PATH is present and it contains the # extra dependency paths. paths = [] for variable in config.snap_env(): if 'LD_LIBRARY_PATH' in variable: these_paths = variable.split('=')[1].strip() paths.extend(these_paths.replace('"', '').split(':')) self.assertTrue(len(paths) > 0, 'Expected LD_LIBRARY_PATH to be in environment') expected = (os.path.join(self.snap_dir, i) for i in ['lib1', 'lib2']) for item in expected: self.assertTrue( item in paths, 'Expected LD_LIBRARY_PATH ({!r}) to include {!r}'.format( paths, item))
def test_invalid_yaml_invalid_confinement_types(self, mock_loadPlugin): invalid_confinement_types = [ 'foo', 'strict-', '_devmode', ] fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) for confinement_type in invalid_confinement_types: with self.subTest(key=confinement_type): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: nothing confinement: {} parts: part1: plugin: go stage-packages: [fswebcam] """.format(confinement_type)) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertEqual( raised.exception.message, "The 'confinement' property does not match the required " "schema: '{}' is not one of ['devmode', 'strict']".format( confinement_type))
def test_config_raises_on_missing_snapcraft_yaml(self): # no snapcraft.yaml with self.assertRaises( project_loader.SnapcraftYamlFileError) as raised: project_loader.Config() self.assertEqual(raised.exception.file, 'snapcraft.yaml')
def test_config_expands_filesets(self, mock_loadPlugin): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: part1: plugin: go stage-packages: [fswebcam] filesets: wget: - /usr/lib/wget.so - /usr/bin/wget build-wget: - /usr/lib/wget.a stage: - $wget - $build-wget snap: - $wget - /usr/share/my-icon.png """) project_loader.Config() mock_loadPlugin.assert_called_with('part1', 'go', { 'snap': ['/usr/lib/wget.so', '/usr/bin/wget', '/usr/share/my-icon.png'], 'stage-packages': ['fswebcam'], 'stage': ['/usr/lib/wget.so', '/usr/bin/wget', '/usr/lib/wget.a'], })
def test_config_loop(self): fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: p1: plugin: tar-content source: . after: [p2] p2: plugin: tar-content source: . after: [p1] """) with self.assertRaises(parts.SnapcraftLogicError) as raised: project_loader.Config() self.assertEqual( raised.exception.message, 'circular dependency chain found in parts definition')
def test_config_adds_vcs_packages_to_build_packages_from_types(self): scenarios = [ ('git', 'git'), ('hg', 'mercurial'), ('mercurial', 'mercurial'), ('bzr', 'bzr'), ('tar', 'tar'), ('svn', 'subversion'), ('subversion', 'subversion'), ] yaml_t = """name: test version: "1" summary: test description: test confinement: strict parts: part1: source: http://something/somewhere source-type: {0} plugin: autotools """ for s in scenarios: with self.subTest(key=(s[1])): self.make_snapcraft_yaml(yaml_t.format(s[0])) c = project_loader.Config() self.assertTrue( s[1] in c.parts.build_tools, '{} not found in {}'.format(s[1], c.parts.build_tools))
def test_config_adds_vcs_packages_to_build_packages(self): scenarios = [ ('git://github.com/ubuntu-core/snapcraft.git', 'git'), ('lp:ubuntu-push', 'bzr'), ('https://github.com/ubuntu-core/snapcraft/archive/2.0.1.tar.gz', 'tar'), ] yaml_t = """name: test version: "1" summary: test description: test confinement: strict parts: part1: source: {0} plugin: autotools """ for s in scenarios: with self.subTest(key=(s[1])): self.make_snapcraft_yaml(yaml_t.format(s[0])) c = project_loader.Config() self.assertTrue( s[1] in c.parts.build_tools, '{} not found in {}'.format(s[1], c.parts.build_tools))
def test_config_runtime_environment_ld(self): # Place a few ld.so.conf files in supported locations. We expect the # contents of these to make it into the LD_LIBRARY_PATH. mesa_dir = os.path.join( self.snap_dir, 'usr', 'lib', 'my_arch', 'mesa') os.makedirs(mesa_dir) with open(os.path.join(mesa_dir, 'ld.so.conf'), 'w') as f: f.write('/mesa') mesa_egl_dir = os.path.join( self.snap_dir, 'usr', 'lib', 'my_arch', 'mesa-egl') os.makedirs(mesa_egl_dir) with open(os.path.join(mesa_egl_dir, 'ld.so.conf'), 'w') as f: f.write('# Standalone comment\n') f.write('/mesa-egl') config = project_loader.Config() environment = config.snap_env() # Ensure that the LD_LIBRARY_PATH includes all the above paths paths = [] for variable in environment: if 'LD_LIBRARY_PATH' in variable: these_paths = variable.split('=')[1].strip() paths.extend(these_paths.replace('"', '').split(':')) self.assertTrue(len(paths) > 0, 'Expected LD_LIBRARY_PATH to be in environment') expected = (os.path.join(self.snap_dir, i) for i in ['mesa', 'mesa-egl']) for item in expected: self.assertTrue(item in paths, 'Expected LD_LIBRARY_PATH to include "{}"'.format( item))
def test_invalid_yaml_invalid_app_names(self, mock_loadPlugin): invalid_app_names = [ '', '-', '--', 'a--a', 'a-', 'a ', ' a', 'a a', '日本語', '한글', 'ру́сский язы́к', 'ໄຂ່ອີສເຕີ້', ':a', 'a:', 'a:a', '_a', 'a_', 'a_a', ] fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) for app_name in invalid_app_names: with self.subTest(key=app_name): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: nothing confinement: strict apps: {!r}: command: foo parts: part1: plugin: nil """.format(app_name)) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertRegex( raised.exception.message, "The 'apps' property does not match the required " "schema.*")
def test_two_snapcraft_yamls_cuase_error(self): open('snapcraft.yaml', 'w').close() open('.snapcraft.yaml', 'w').close() with self.assertRaises(EnvironmentError) as raised: project_loader.Config() self.assertEqual( str(raised.exception), "Found a 'snapcraft.yaml' and a '.snapcraft.yaml', " "please remove one")
def test_config_snap_environment_with_no_library_paths(self): config = project_loader.Config() environment = config.snap_env() self.assertTrue( 'PATH="{0}/bin:{0}/usr/bin:$PATH"'.format(self.snap_dir) in environment, 'Current PATH is {!r}'.format(environment)) for e in environment: self.assertFalse('LD_LIBRARY_PATH' in e, 'Current environment is {!r}'.format(e))
def test_visible_snapcraft_yaml_loads(self): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: main: plugin: nil """) project_loader.Config()
def test_hidden_snapcraft_yaml_loads(self): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: main: plugin: nil """) os.rename('snapcraft.yaml', '.snapcraft.yaml') project_loader.Config()
def test_config_snap_environment_with_dependencies_but_no_paths( self, mock_get_dependencies): library_paths = { os.path.join(self.snap_dir, 'lib1'), os.path.join(self.snap_dir, 'lib2'), } mock_get_dependencies.return_value = library_paths config = project_loader.Config() # Ensure that LD_LIBRARY_PATH is present, but is completey empty since # no library paths actually exist. for variable in config.snap_env(): self.assertFalse( 'LD_LIBRARY_PATH' in variable, 'Expected no LD_LIBRARY_PATH (got {!r})'.format(variable))
def test_config_loads_plugins(self, mock_loadPlugin): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: part1: plugin: go stage-packages: [fswebcam] """) project_loader.Config() mock_loadPlugin.assert_called_with('part1', 'go', { 'stage-packages': ['fswebcam'], 'stage': [], 'snap': [], })
def test_config_composes_with_remote_parts(self, mock_loadPlugin): self.useFixture(fixture_setup.FakeParts()) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: part1: stage-packages: [fswebcam] """) parts.update() project_loader.Config() mock_loadPlugin.assert_called_with('part1', 'go', { 'source': 'http://source.tar.gz', 'stage-packages': ['fswebcam'], 'stage': [], 'snap': []})
def test_config_adds_extra_build_tools_when_cross_compiling(self): with unittest.mock.patch('platform.machine') as machine_mock: machine_mock.return_value = 'x86_64' project_options = snapcraft.ProjectOptions(target_deb_arch='armhf') yaml = """name: test version: "1" summary: test description: test confinement: strict parts: part1: plugin: nil """ self.make_snapcraft_yaml(yaml) config = project_loader.Config(project_options) self.assertEqual(config.parts.build_tools, ['gcc-arm-linux-gnueabihf'])
def test_config_has_no_extra_build_tools_when_not_cross_compiling(self): class ProjectOptionsFake(snapcraft.ProjectOptions): @property def is_cross_compiling(self): return False yaml = """name: test version: "1" summary: test description: test confinement: strict parts: part1: plugin: nil """ self.make_snapcraft_yaml(yaml) config = project_loader.Config(ProjectOptionsFake()) self.assertEqual(config.parts.build_tools, [])
def test_get_dependents(self): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: main: plugin: nil dependent: plugin: nil after: [main] """) config = project_loader.Config() self.assertFalse(config.parts.get_dependents('dependent')) self.assertEqual({'dependent'}, config.parts.get_dependents('main'))
def test_invalid_yaml_missing_description(self, mock_loadPlugin): fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) self.make_snapcraft_yaml("""name: test version: "1" summary: test confinement: strict parts: part1: plugin: go stage-packages: [fswebcam] """) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertEqual( raised.exception.message, "'description' is a required property")
def test_invalid_yaml_invalid_name_as_number(self, mock_loadPlugin): fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) self.make_snapcraft_yaml("""name: 1 version: "1" summary: test description: nothing confinement: strict parts: part1: plugin: go stage-packages: [fswebcam] """) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertEqual(raised.exception.message, "The 'name' property does not match the required " "schema: 1 is not of type 'string'")
def test_invalid_yaml_invalid_icon_extension(self, mock_loadPlugin): fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test icon: icon.foo confinement: strict parts: part1: plugin: go stage-packages: [fswebcam] """) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertEqual(raised.exception.message, "'icon' must be either a .png or a .svg")
def test_invalid_yaml_invalid_epochs(self, mock_loadPlugin): invalid_epochs = [ '0*', '_', '1-', '1+', '-1', '-1*', 'a', '1a', '1**', '"01"', '1.2', '"1.2"', '[1]' ] fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) for epoch in invalid_epochs: with self.subTest(key=epoch): self.make_snapcraft_yaml("""name: test version: "1" summary: test description: nothing epoch: {} parts: part1: plugin: go stage-packages: [fswebcam] """.format(epoch)) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertRegex( raised.exception.message, "The 'epoch' property does not match the required " "schema:.*is not a 'epoch' \(epochs are positive integers " "followed by an optional asterisk\)")
def test_config_composes_with_a_non_existent_remote_part(self): self.useFixture(fixture_setup.FakeParts()) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: non-existing-part: stage-packages: [fswebcam] """) parts.update() with self.assertRaises(parts.SnapcraftLogicError) as raised: project_loader.Config() self.assertEqual( str(raised.exception), '{!r} is missing the `plugin` entry and is not defined in the ' 'current remote parts cache, try to run `snapcraft update` ' 'to refresh'.format('non-existing-part'))
def test_config_uses_remote_part_from_after(self, mock_load): self.useFixture(fixture_setup.FakeParts()) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: part1: after: - curl plugin: go stage-packages: [fswebcam] """) def load_effect(*args, **kwargs): mock_part = unittest.mock.Mock() mock_part.code.build_packages = [] mock_part.deps = [] mock_part.name = args[0] return mock_part mock_load.side_effect = load_effect project_options = snapcraft.ProjectOptions() parts.update() project_loader.Config(project_options) call1 = unittest.mock.call('part1', 'go', { 'stage': [], 'snap': [], 'stage-packages': ['fswebcam']}, project_options, self.part_schema) call2 = unittest.mock.call('curl', 'autotools', { 'source': 'http://curl.org'}, project_options, self.part_schema) mock_load.assert_has_calls([call1, call2])
def test_config_loads_with_different_encodings( self, mock_loadPlugin): content = """name: test version: "1" summary: test description: ñoño test confinement: strict parts: part1: plugin: go stage-packages: [fswebcam] """ for enc in ['utf-8', 'utf-8-sig', 'utf-16']: with self.subTest(key=enc): self.make_snapcraft_yaml(content, encoding=enc) project_loader.Config() mock_loadPlugin.assert_called_with('part1', 'go', { 'stage-packages': ['fswebcam'], 'stage': [], 'snap': [], })
def test_tab_in_yaml(self, mock_loadPlugin): fake_logger = fixtures.FakeLogger(level=logging.ERROR) self.useFixture(fake_logger) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: nothing \tconfinement: strict parts: part1: plugin: go stage-packages: [fswebcam] """) with self.assertRaises(SnapcraftSchemaError) as raised: project_loader.Config() self.assertEqual( raised.exception.message, 'found character \'\\t\' that cannot start any token ' 'on line 4 of snapcraft.yaml')
def test_config_after_is_an_undefined_part(self): self.useFixture(fixture_setup.FakeParts()) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: test confinement: strict parts: part1: plugin: nil after: [non-existing-part] """) parts.update() with self.assertRaises(parts.SnapcraftLogicError) as raised: project_loader.Config() self.assertEqual( str(raised.exception), 'Cannot find definition for part {!r}. It may be a ' 'remote part, run `snapcraft update` to ' 'refresh the remote parts cache'.format('non-existing-part'))
def test_yaml_missing_confinement_must_log(self, mock_loadPlugin): fake_logger = fixtures.FakeLogger(level=logging.WARNING) self.useFixture(fake_logger) self.make_snapcraft_yaml("""name: test version: "1" summary: test description: nothing parts: part1: plugin: go stage-packages: [fswebcam] """) c = project_loader.Config() # Verify the default is "strict" self.assertTrue('confinement' in c.data, 'Expected "confinement" property to be in snap.yaml') self.assertEqual(c.data['confinement'], 'strict') self.assertTrue( '"confinement" property not specified: defaulting to "strict"' in fake_logger.output, 'Missing confinement hint in output')