Ejemplo n.º 1
0
def test_build_generics_different_filetype(tmp_path, caplog, monkeypatch):
    """Ignores whatever is not a regular file, symlink or dir."""
    caplog.set_level(logging.DEBUG)

    # change into the tmp path and do everything locally, because otherwise the socket path
    # will be too long for mac os
    monkeypatch.chdir(tmp_path)

    build_dir = pathlib.Path(BUILD_DIRNAME)
    build_dir.mkdir()
    entrypoint = pathlib.Path('crazycharm.py')
    entrypoint.touch()

    # create a socket
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.bind('test-socket')

    builder = Builder({
        'from': tmp_path,
        'entrypoint': tmp_path / entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    assert not (build_dir / 'test-socket').exists()
    expected = "Ignoring file because of type: 'test-socket'"
    assert expected in [rec.message for rec in caplog.records]
Ejemplo n.º 2
0
def test_build_dependencies_needs_system(tmp_path, config):
    """pip3 is called with --system when pip3 needs it."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": "whatever",
            "requirement": ["reqs"],
        },
        config,
    )

    with patch("charmcraft.commands.build._pip_needs_system") as is_bionic:
        is_bionic.return_value = True
        with patch("charmcraft.commands.build.polite_exec") as mock:
            mock.return_value = 0
            builder.handle_dependencies()

    envpath = build_dir / VENV_DIRNAME
    assert mock.mock_calls == [
        call(["pip3", "list"]),
        call([
            "pip3",
            "install",
            "--target={}".format(envpath),
            "--system",
            "--requirement=reqs",
        ]),
    ]
Ejemplo n.º 3
0
def test_build_dependencies_virtualenv_multiple(tmp_path, config):
    """A virtualenv is created with multiple requirements files."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": "whatever",
            "requirement": ["reqs1.txt", "reqs2.txt"],
        },
        config,
    )

    with patch("charmcraft.commands.build.polite_exec") as mock:
        mock.return_value = 0
        builder.handle_dependencies()

    envpath = build_dir / VENV_DIRNAME
    assert mock.mock_calls == [
        call(["pip3", "list"]),
        call([
            "pip3",
            "install",
            "--target={}".format(envpath),
            "--requirement=reqs1.txt",
            "--requirement=reqs2.txt",
        ]),
    ]
Ejemplo n.º 4
0
def test_build_dependencies_needs_system(tmp_path):
    """pip3 is called with --system when pip3 needs it."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': ['reqs'],
    })

    with patch('charmcraft.commands.build._pip_needs_system') as is_bionic:
        is_bionic.return_value = True
        with patch('charmcraft.commands.build.polite_exec') as mock:
            mock.return_value = 0
            builder.handle_dependencies()

    envpath = build_dir / VENV_DIRNAME
    assert mock.mock_calls == [
        call(['pip3', 'list']),
        call([
            'pip3', 'install', '--target={}'.format(envpath), '--system',
            '--requirement=reqs'
        ]),
    ]
Ejemplo n.º 5
0
def test_build_dispatcher_classic_hooks_linking_charm_replaced(
        tmp_path, caplog):
    """Hooks that are just a symlink to the entrypoint are replaced."""
    caplog.set_level(logging.DEBUG, logger="charmcraft")

    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # simple source code
    src_dir = build_dir / 'src'
    src_dir.mkdir()
    built_charm_script = src_dir / 'charm.py'
    with built_charm_script.open('wb') as fh:
        fh.write(b'all the magic')

    # a test hook, just a symlink to the charm
    built_hooks_dir = build_dir / 'hooks'
    built_hooks_dir.mkdir()
    test_hook = built_hooks_dir / 'somehook'
    test_hook.symlink_to(built_charm_script)

    included_dispatcher = build_dir / DISPATCH_FILENAME

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': [],
    })
    builder.handle_dispatcher(built_charm_script)

    # the test hook is still there and a symlink, but now pointing to the dispatcher
    assert test_hook.is_symlink()
    assert test_hook.resolve() == included_dispatcher
    expected = "Replacing existing hook 'somehook' as it's a symlink to the entrypoint"
    assert expected in [rec.message for rec in caplog.records]
Ejemplo n.º 6
0
def test_build_code_optional_bogus(tmp_path, monkeypatch):
    """Check that CHARM_OPTIONAL controls what gets copied."""
    monkeypatch.setattr(build, 'CHARM_OPTIONAL', ['foo.yaml'])

    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / 'charm.py'

    config = tmp_path / 'config.yaml'
    config.touch()
    foo = tmp_path / 'foo.yaml'
    foo.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_code()

    built_config = build_dir / 'config.yaml'
    built_foo = build_dir / 'foo.yaml'

    # config.yaml is not in the build
    assert not built_config.exists()
    # but foo.yaml is
    assert built_foo.is_symlink()
    assert built_foo.resolve() == foo
Ejemplo n.º 7
0
def test_build_code_optional(tmp_path, optional):
    """Check transferred 'optional' files."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / 'charm.py'

    config = tmp_path / 'config.yaml'
    actions = tmp_path / 'actions.yaml'
    if 'config' in optional:
        config.touch()
    if 'actions' in optional:
        actions.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_code()

    built_config = build_dir / 'config.yaml'
    built_actions = build_dir / 'actions.yaml'

    if 'config' in optional:
        assert built_config.is_symlink()
        assert built_config.resolve() == config
    else:
        assert not built_config.exists()
    if 'actions' in optional:
        assert built_actions.is_symlink()
        assert built_actions.resolve() == actions
    else:
        assert not built_actions.exists()
Ejemplo n.º 8
0
def test_build_code_simple(tmp_path):
    """Check transferred metadata and simple entrypoint."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    metadata = tmp_path / CHARM_METADATA
    metadata.touch()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    linked_entrypoint = builder.handle_code()

    built_metadata = build_dir / CHARM_METADATA
    assert built_metadata.is_symlink()
    assert built_metadata.resolve() == metadata

    built_entrypoint = build_dir / 'crazycharm.py'
    assert built_entrypoint.is_symlink()
    assert built_entrypoint.resolve() == entrypoint

    assert linked_entrypoint == built_entrypoint
Ejemplo n.º 9
0
def test_build_generics_simple_files(tmp_path):
    """Check transferred metadata and simple entrypoint, also return proper linked entrypoint."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    metadata = tmp_path / CHARM_METADATA
    metadata.touch()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    linked_entrypoint = builder.handle_generic_paths()

    # check files are there, are files, and are really hard links (so no
    # check for permissions needed)
    built_metadata = build_dir / CHARM_METADATA
    assert built_metadata.is_file()
    assert built_metadata.stat().st_ino == metadata.stat().st_ino

    built_entrypoint = build_dir / 'crazycharm.py'
    assert built_entrypoint.is_file()
    assert built_entrypoint.stat().st_ino == entrypoint.stat().st_ino

    assert linked_entrypoint == built_entrypoint
Ejemplo n.º 10
0
def test_build_generics_symlink_directory_outside(tmp_path, caplog):
    """Ignores (with warning) a symlink pointing a dir outside projects dir."""
    caplog.set_level(logging.WARNING)

    project_dir = tmp_path / 'test-project'
    project_dir.mkdir()

    build_dir = project_dir / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = project_dir / 'crazycharm.py'
    entrypoint.touch()

    outside_project = tmp_path / 'dangerous'
    outside_project.mkdir()
    the_symlink = project_dir / 'external-dir'
    the_symlink.symlink_to(outside_project)

    builder = Builder({
        'from': project_dir,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    assert not (build_dir / 'external-dir').exists()
    expected = "Ignoring symlink because targets outside the project: 'external-dir'"
    assert expected in [rec.message for rec in caplog.records]
Ejemplo n.º 11
0
def test_build_generics_ignored_dir(tmp_path, caplog):
    """Don't include ignored dir."""
    caplog.set_level(logging.DEBUG)
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create two files (and the needed entrypoint)
    dir1 = tmp_path / 'dir1'
    dir1.mkdir()
    dir2 = tmp_path / 'dir2'
    dir2.mkdir()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })

    # set it up to ignore dir 2 and make it work
    builder.ignore_rules.extend_patterns(['dir2'])
    builder.handle_generic_paths()

    assert (build_dir / 'dir1').exists()
    assert not (build_dir / 'dir2').exists()

    expected = "Ignoring directory because of rules: 'dir2'"
    assert expected in [rec.message for rec in caplog.records]
Ejemplo n.º 12
0
def test_build_generics_symlink_dir(tmp_path):
    """Respects a symlinked dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()
    somedir = tmp_path / 'somedir'
    somedir.mkdir()
    somefile = somedir / 'sanity check'
    somefile.touch()
    the_symlink = tmp_path / 'thelink'
    the_symlink.symlink_to(somedir)

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    built_symlink = build_dir / 'thelink'
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / 'somedir'
    real_link = os.readlink(str(built_symlink))
    assert real_link == 'somedir'

    # as a sanity check, the file inside the linked dir should exist
    assert (build_dir / 'thelink' / 'sanity check').exists()
Ejemplo n.º 13
0
def test_build_generics_symlink_deep(tmp_path, config):
    """Correctly re-links a symlink across deep dirs."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()

    dir1 = tmp_path / "dir1"
    dir1.mkdir()
    dir2 = tmp_path / "dir2"
    dir2.mkdir()
    original_target = dir1 / "file.real"
    original_target.touch()
    the_symlink = dir2 / "file.link"
    the_symlink.symlink_to(original_target)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_symlink = build_dir / "dir2" / "file.link"
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / "dir1" / "file.real"
    real_link = os.readlink(str(built_symlink))
    assert real_link == "../dir1/file.real"
Ejemplo n.º 14
0
def test_build_generics_symlink_file_outside(tmp_path, caplog, config):
    """Ignores (with warning) a symlink pointing a file outside projects dir."""
    caplog.set_level(logging.WARNING)

    project_dir = tmp_path / "test-project"
    project_dir.mkdir()

    build_dir = project_dir / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = project_dir / "crazycharm.py"
    entrypoint.touch()

    outside_project = tmp_path / "dangerous.txt"
    outside_project.touch()
    the_symlink = project_dir / "external-file"
    the_symlink.symlink_to(outside_project)

    builder = Builder(
        {
            "from": project_dir,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    assert not (build_dir / "external-file").exists()
    expected = "Ignoring symlink because targets outside the project: 'external-file'"
    assert expected in [rec.message for rec in caplog.records]
Ejemplo n.º 15
0
def test_build_dispatcher_classic_hooks_mandatory_respected(tmp_path, config):
    """The already included mandatory classic hooks are left untouched."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    built_hooks_dir = build_dir / "hooks"
    built_hooks_dir.mkdir()
    test_hook = built_hooks_dir / "testhook"
    with test_hook.open("wb") as fh:
        fh.write(b"abc")

    linked_entrypoint = build_dir / "somestuff.py"

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": "whatever",
            "requirement": [],
        },
        config,
    )
    with patch("charmcraft.commands.build.MANDATORY_HOOK_NAMES", {"testhook"}):
        builder.handle_dispatcher(linked_entrypoint)

    with test_hook.open("rb") as fh:
        assert fh.read() == b"abc"
Ejemplo n.º 16
0
def test_build_generics_symlink_deep(tmp_path):
    """Correctly re-links a symlink across deep dirs."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()
    entrypoint = tmp_path / 'crazycharm.py'
    entrypoint.touch()

    dir1 = tmp_path / 'dir1'
    dir1.mkdir()
    dir2 = tmp_path / 'dir2'
    dir2.mkdir()
    original_target = dir1 / 'file.real'
    original_target.touch()
    the_symlink = dir2 / 'file.link'
    the_symlink.symlink_to(original_target)

    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_generic_paths()

    built_symlink = build_dir / 'dir2' / 'file.link'
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / 'dir1' / 'file.real'
    real_link = os.readlink(str(built_symlink))
    assert real_link == '../dir1/file.real'
Ejemplo n.º 17
0
def test_build_generics_symlink_dir(tmp_path, config):
    """Respects a symlinked dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()
    somedir = tmp_path / "somedir"
    somedir.mkdir()
    somefile = somedir / "sanity check"
    somefile.touch()
    the_symlink = tmp_path / "thelink"
    the_symlink.symlink_to(somedir)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_symlink = build_dir / "thelink"
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / "somedir"
    real_link = os.readlink(str(built_symlink))
    assert real_link == "somedir"

    # as a sanity check, the file inside the linked dir should exist
    assert (build_dir / "thelink" / "sanity check").exists()
Ejemplo n.º 18
0
def test_build_generics_symlink_file(tmp_path, config):
    """Respects a symlinked file."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()
    the_symlink = tmp_path / "somehook.py"
    the_symlink.symlink_to(entrypoint)

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )
    builder.handle_generic_paths()

    built_symlink = build_dir / "somehook.py"
    assert built_symlink.is_symlink()
    assert built_symlink.resolve() == build_dir / "crazycharm.py"
    real_link = os.readlink(str(built_symlink))
    assert real_link == "crazycharm.py"
Ejemplo n.º 19
0
def test_build_generics_ignored_file(tmp_path, caplog, config):
    """Don't include ignored filed."""
    caplog.set_level(logging.DEBUG)
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # create two files (and the needed entrypoint)
    file1 = tmp_path / "file1.txt"
    file1.touch()
    file2 = tmp_path / "file2.txt"
    file2.touch()
    entrypoint = tmp_path / "crazycharm.py"
    entrypoint.touch()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": entrypoint,
            "requirement": [],
        },
        config,
    )

    # set it up to ignore file 2 and make it work
    builder.ignore_rules.extend_patterns(["file2.*"])
    builder.handle_generic_paths()

    assert (build_dir / "file1.txt").exists()
    assert not (build_dir / "file2.txt").exists()

    expected = "Ignoring file because of rules: 'file2.txt'"
    assert expected in [rec.message for rec in caplog.records]
Ejemplo n.º 20
0
def test_build_basic_complete_structure(tmp_path, monkeypatch, config):
    """Integration test: a simple structure with custom lib and normal src dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # the metadata (save it and restore to later check)
    metadata_data = {"name": "name-from-metadata"}
    metadata_file = tmp_path / "metadata.yaml"
    metadata_raw = yaml.dump(metadata_data).encode("ascii")
    with metadata_file.open("wb") as fh:
        fh.write(metadata_raw)

    # a lib dir
    lib_dir = tmp_path / "lib"
    lib_dir.mkdir()
    ops_lib_dir = lib_dir / "ops"
    ops_lib_dir.mkdir()
    ops_stuff = ops_lib_dir / "stuff.txt"
    with ops_stuff.open("wb") as fh:
        fh.write(b"ops stuff")

    # simple source code
    src_dir = tmp_path / "src"
    src_dir.mkdir()
    charm_script = src_dir / "charm.py"
    with charm_script.open("wb") as fh:
        fh.write(b"all the magic")

    monkeypatch.chdir(tmp_path)  # so the zip file is left in the temp dir
    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": charm_script,
            "requirement": [],
        },
        config,
    )
    zipname = builder.run()

    # check all is properly inside the zip
    # contents!), and all relative to build dir
    zf = zipfile.ZipFile(zipname)
    assert zf.read("metadata.yaml") == metadata_raw
    assert zf.read("src/charm.py") == b"all the magic"
    dispatch = DISPATCH_CONTENT.format(
        entrypoint_relative_path="src/charm.py").encode("ascii")
    assert zf.read("dispatch") == dispatch
    assert zf.read("hooks/install") == dispatch
    assert zf.read("hooks/start") == dispatch
    assert zf.read("hooks/upgrade-charm") == dispatch
    assert zf.read("lib/ops/stuff.txt") == b"ops stuff"

    # check the manifest is present and with particular values that depend on given info
    manifest = yaml.safe_load(zf.read("manifest.yaml"))
    assert (manifest["charmcraft-started-at"] ==
            config.project.started_at.isoformat() + "Z")
Ejemplo n.º 21
0
def test_build_basic_complete_structure(tmp_path, monkeypatch, config):
    """Integration test: a simple structure with custom lib and normal src dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # the metadata (save it and restore to later check)
    metadata_data = {'name': 'name-from-metadata'}
    metadata_file = tmp_path / 'metadata.yaml'
    metadata_raw = yaml.dump(metadata_data).encode('ascii')
    with metadata_file.open('wb') as fh:
        fh.write(metadata_raw)

    # a lib dir
    lib_dir = tmp_path / 'lib'
    lib_dir.mkdir()
    ops_lib_dir = lib_dir / 'ops'
    ops_lib_dir.mkdir()
    ops_stuff = ops_lib_dir / 'stuff.txt'
    with ops_stuff.open('wb') as fh:
        fh.write(b'ops stuff')

    # simple source code
    src_dir = tmp_path / 'src'
    src_dir.mkdir()
    charm_script = src_dir / 'charm.py'
    with charm_script.open('wb') as fh:
        fh.write(b'all the magic')

    monkeypatch.chdir(tmp_path)  # so the zip file is left in the temp dir
    builder = Builder(
        {
            'from': tmp_path,
            'entrypoint': charm_script,
            'requirement': [],
        }, config)
    zipname = builder.run()

    # check all is properly inside the zip
    # contents!), and all relative to build dir
    zf = zipfile.ZipFile(zipname)
    assert zf.read('metadata.yaml') == metadata_raw
    assert zf.read('src/charm.py') == b"all the magic"
    dispatch = DISPATCH_CONTENT.format(
        entrypoint_relative_path='src/charm.py').encode('ascii')
    assert zf.read('dispatch') == dispatch
    assert zf.read('hooks/install') == dispatch
    assert zf.read('hooks/start') == dispatch
    assert zf.read('hooks/upgrade-charm') == dispatch
    assert zf.read('lib/ops/stuff.txt') == b"ops stuff"

    # check the manifest is present and with particular values that depend on given info
    manifest = yaml.safe_load(zf.read('manifest.yaml'))
    assert manifest[
        'charmcraft-started-at'] == config.project.started_at.isoformat() + "Z"
Ejemplo n.º 22
0
def test_builder_without_jujuignore(tmp_path):
    """Without a .jujuignore we still have a default set of ignores"""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': [],
    })
    ignore = builder._load_juju_ignore()
    assert ignore.match('/.git', is_dir=True)
    assert ignore.match('/build', is_dir=True)
    assert not ignore.match('myfile.py', is_dir=False)
Ejemplo n.º 23
0
def test_build_basic_complete_structure(tmp_path, monkeypatch):
    """Integration test: a simple structure with custom lib and normal src dir."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    # the metadata (save it and restore to later check)
    metadata_data = {'name': 'name-from-metadata'}
    metadata_file = tmp_path / 'metadata.yaml'
    metadata_raw = yaml.dump(metadata_data).encode('ascii')
    with metadata_file.open('wb') as fh:
        fh.write(metadata_raw)

    # a lib dir
    lib_dir = tmp_path / 'lib'
    lib_dir.mkdir()
    ops_lib_dir = lib_dir / 'ops'
    ops_lib_dir.mkdir()
    ops_stuff = ops_lib_dir / 'stuff.txt'
    with ops_stuff.open('wb') as fh:
        fh.write(b'ops stuff')

    # simple source code
    src_dir = tmp_path / 'src'
    src_dir.mkdir()
    charm_script = src_dir / 'charm.py'
    with charm_script.open('wb') as fh:
        fh.write(b'all the magic')

    monkeypatch.chdir(tmp_path)  # so the zip file is left in the temp dir
    builder = Builder({
        'from': pathlib.Path(
            str(tmp_path)),  # bad support for tmp_path's pathlib2 in Py3.5
        'entrypoint': pathlib.Path(str(charm_script)),
        'requirement': [],
    })
    zipname = builder.run()

    # check all is properly inside the zip
    # contents!), and all relative to build dir
    zf = zipfile.ZipFile(zipname)
    assert zf.read('metadata.yaml') == metadata_raw
    assert zf.read('src/charm.py') == b"all the magic"
    dispatch = DISPATCH_CONTENT.format(
        entrypoint_relative_path='src/charm.py').encode('ascii')
    assert zf.read('dispatch') == dispatch
    assert zf.read('hooks/install') == dispatch
    assert zf.read('hooks/start') == dispatch
    assert zf.read('hooks/upgrade-charm') == dispatch
    assert zf.read('lib/ops/stuff.txt') == b"ops stuff"
Ejemplo n.º 24
0
def test_build_dependencies_virtualenv_none(tmp_path):
    """The virtualenv is NOT created if no needed."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': [],
    })

    with patch('charmcraft.commands.build.polite_exec') as mock:
        builder.handle_dependencies()

    mock.assert_not_called()
Ejemplo n.º 25
0
def test_build_dependencies_virtualenv_error_installing(tmp_path):
    """Process is properly interrupted if virtualenv creation fails."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': ['something'],
    })

    with patch('charmcraft.commands.build.polite_exec') as mock:
        mock.side_effect = [0, -7]
        with pytest.raises(CommandError, match="problems installing dependencies"):
            builder.handle_dependencies()
Ejemplo n.º 26
0
def test_build_dependencies_virtualenv_error_basicpip(tmp_path):
    """Process is properly interrupted if using pip fails."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': ['something'],
    })

    with patch('charmcraft.commands.build.polite_exec') as mock:
        mock.return_value = -7
        with pytest.raises(CommandError, match="problems using pip"):
            builder.handle_dependencies()
Ejemplo n.º 27
0
def test_build_code_includes_templates(tmp_path):
    """If 'templates' exists, it is included in the build tree."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    source_dir = tmp_path / "templates"
    entrypoint = tmp_path / 'charm.py'
    source_dir.mkdir()
    builder = Builder({
        'from': tmp_path,
        'entrypoint': entrypoint,
        'requirement': [],
    })
    builder.handle_code()
    built_dir = build_dir / 'templates'
    assert built_dir.is_symlink()
    assert built_dir.resolve() == source_dir
Ejemplo n.º 28
0
def test_builder_without_jujuignore(tmp_path, config):
    """Without a .jujuignore we still have a default set of ignores"""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": "whatever",
            "requirement": [],
        },
        config,
    )
    ignore = builder._load_juju_ignore()
    assert ignore.match("/.git", is_dir=True)
    assert ignore.match("/build", is_dir=True)
    assert not ignore.match("myfile.py", is_dir=False)
Ejemplo n.º 29
0
def test_build_dispatcher_modern_dispatch_respected(tmp_path):
    """The already included dispatcher script is left untouched."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    already_present_dispatch = build_dir / DISPATCH_FILENAME
    with already_present_dispatch.open('wb') as fh:
        fh.write(b'abc')

    builder = Builder({
        'from': tmp_path,
        'entrypoint': 'whatever',
        'requirement': [],
    })
    builder.handle_dispatcher('whatever')

    with already_present_dispatch.open('rb') as fh:
        assert fh.read() == b'abc'
Ejemplo n.º 30
0
def test_build_dependencies_virtualenv_error_basicpip(tmp_path, config):
    """Process is properly interrupted if using pip fails."""
    build_dir = tmp_path / BUILD_DIRNAME
    build_dir.mkdir()

    builder = Builder(
        {
            "from": tmp_path,
            "entrypoint": "whatever",
            "requirement": ["something"],
        },
        config,
    )

    with patch("charmcraft.commands.build.polite_exec") as mock:
        mock.return_value = -7
        with pytest.raises(CommandError, match="problems using pip"):
            builder.handle_dependencies()