Exemple #1
0
def test_initmsg_debug(monkeypatch):
    """When in DEBUG, the init msg goes both to disk and terminal."""
    monkeypatch.setenv('DEBUG', '1')

    cmd = create_command('somecommand')
    fake_stream = io.StringIO()
    with patch('charmcraft.main.COMMAND_GROUPS',
               [('test-group', 'whatever title', [cmd])]):
        with patch.object(logsetup.message_handler,
                          'ended_ok') as ended_ok_mock:
            with patch.object(logsetup.message_handler._stderr_handler,
                              'stream', fake_stream):
                main(['charmcraft', 'somecommand'])

    # get the logfile first line before removing it
    ended_ok_mock.assert_called_once_with()
    logged_to_file = pathlib.Path(
        logsetup.message_handler._log_filepath).read_text()
    file_first_line = logged_to_file.split('\n')[0]
    logsetup.message_handler.ended_ok()

    # get the terminal first line
    captured = fake_stream.getvalue()
    terminal_first_line = captured.split('\n')[0]

    expected = "Starting charmcraft version " + __version__
    assert expected in file_first_line
    assert expected in terminal_first_line
Exemple #2
0
def test_initmsg_verbose():
    """In verbose mode, the init msg goes both to disk and terminal."""
    cmd = create_command("somecommand")
    fake_stream = io.StringIO()
    with patch("charmcraft.main.COMMAND_GROUPS",
               [("test-group", "whatever title", [cmd])]):
        with patch.object(logsetup.message_handler,
                          "ended_ok") as ended_ok_mock:
            with patch.object(logsetup.message_handler._stderr_handler,
                              "stream", fake_stream):
                main(["charmcraft", "--verbose", "somecommand"])

    # get the logfile first line before removing it
    ended_ok_mock.assert_called_once_with()
    logged_to_file = pathlib.Path(
        logsetup.message_handler._log_filepath).read_text()
    file_first_line = logged_to_file.split("\n")[0]
    logsetup.message_handler.ended_ok()

    # get the terminal first line
    captured = fake_stream.getvalue()
    terminal_first_line = captured.split("\n")[0]

    expected = "Starting charmcraft version " + __version__
    assert expected in file_first_line
    assert expected in terminal_first_line
Exemple #3
0
def test_main_logs_system_details(emitter, config):
    """Calling main ends up logging the system details."""
    system_details = "test system details"

    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as run_mock:
            with patch("charmcraft.main._get_system_details") as details_mock:
                details_mock.return_value = system_details
                run_mock.return_value = None
                main(["charmcraft", "version"])
    emit_mock.trace.assert_called_once_with(system_details)
Exemple #4
0
def test_main_managed_instance(monkeypatch):
    """Init emitter with a specific log filepath."""
    monkeypatch.setenv("CHARMCRAFT_MANAGED_MODE", "1")

    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.return_value = None
            main(["charmcraft", "version"])

    # check how Emitter was initted
    emit_mock.init.assert_called_once_with(
        EmitterMode.NORMAL,
        "charmcraft",
        f"Starting charmcraft version {__version__}",
        log_filepath=env.get_managed_environment_log_path(),
    )
Exemple #5
0
def test_main_no_args():
    """The setup.py entry_point function needs to work with no arguments."""
    with patch("sys.argv", ["charmcraft"]):
        with patch("charmcraft.main.message_handler") as mh_mock:
            retcode = main()

    assert retcode == 1
    assert mh_mock.ended_cmderror.call_count == 1
Exemple #6
0
def test_main_controlled_return_code():
    """Work ended ok, and the command indicated the return code."""
    with patch("charmcraft.main.message_handler") as mh_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.return_value = 9
            retcode = main(["charmcraft", "version"])

    assert retcode == 9
    mh_mock.ended_ok.assert_called_once_with()
Exemple #7
0
def test_main_ok():
    """Work ended ok: message handler notified properly, return code in 0."""
    with patch.object(logsetup, 'message_handler') as mh_mock:
        with patch('charmcraft.main.Dispatcher.run') as d_mock:
            d_mock.return_value = None
            retcode = main(['charmcraft', 'version'])

    assert retcode == 0
    assert mh_mock.ended_ok.called_once()
Exemple #8
0
def test_main_interrupted():
    """Work interrupted: message handler notified properly, return code in 1."""
    with patch.object(logsetup, 'message_handler') as mh_mock:
        with patch('charmcraft.main.Dispatcher.run') as d_mock:
            d_mock.side_effect = KeyboardInterrupt
            retcode = main(['charmcraft', 'version'])

    assert retcode == 1
    assert mh_mock.ended_interrupt.called_once()
Exemple #9
0
def test_main_controlled_return_code(base_config_present):
    """Work ended ok, and the command indicated the return code."""
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.return_value = 9
            retcode = main(["charmcraft", "version"])

    assert retcode == 9
    emit_mock.ended_ok.assert_called_once_with()
Exemple #10
0
def test_main_ok():
    """Work ended ok: message handler notified properly, return code in 0."""
    with patch("charmcraft.main.message_handler") as mh_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.return_value = None
            retcode = main(["charmcraft", "version"])

    assert retcode == 0
    mh_mock.ended_ok.assert_called_once_with()
Exemple #11
0
def test_main_interrupted():
    """Work interrupted: message handler notified properly, return code in 1."""
    with patch("charmcraft.main.message_handler") as mh_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = KeyboardInterrupt
            retcode = main(["charmcraft", "version"])

    assert retcode == 1
    assert mh_mock.ended_interrupt.call_count == 1
Exemple #12
0
def test_main_no_args():
    """The setup.py entry_point function needs to work with no arguments."""
    with patch('sys.argv', ['charmcraft']):
        with patch.object(logsetup, 'message_handler') as mh_mock:
            with patch('charmcraft.main.Dispatcher.run') as d_mock:
                d_mock.side_effect = CommandError('boom', retcode=42)
                retcode = main()

    assert retcode == 42
    assert mh_mock.ended_ok.called_once()
Exemple #13
0
def test_main_crash():
    """Work crashed: message handler notified properly, return code in 1."""
    simulated_exception = ValueError('boom')
    with patch.object(logsetup, 'message_handler') as mh_mock:
        with patch('charmcraft.main.Dispatcher.run') as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(['charmcraft', 'version'])

    assert retcode == 1
    assert mh_mock.ended_crash.called_once_with(simulated_exception)
Exemple #14
0
def test_main_controlled_error():
    """Work raised CommandError: message handler notified properly, use indicated return code."""
    simulated_exception = CommandError("boom", retcode=33)
    with patch("charmcraft.main.message_handler") as mh_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(["charmcraft", "version"])

    assert retcode == 33
    mh_mock.ended_cmderror.assert_called_once_with(simulated_exception)
Exemple #15
0
def test_main_controlled_error(base_config_present):
    """Work raised CraftError: message handler notified properly, use indicated return code."""
    simulated_exception = CraftError("boom", retcode=33)
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(["charmcraft", "version"])

    assert retcode == 33
    emit_mock.error.assert_called_once_with(simulated_exception)
Exemple #16
0
def test_main_crash():
    """Work crashed: message handler notified properly, return code in 1."""
    simulated_exception = ValueError("boom")
    with patch("charmcraft.main.message_handler") as mh_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(["charmcraft", "version"])

    assert retcode == 1
    mh_mock.ended_crash.assert_called_once_with(simulated_exception)
Exemple #17
0
def test_main_controlled_error():
    """Work raised CommandError: message handler notified properly, use indicated return code."""
    simulated_exception = CommandError('boom', retcode=33)
    with patch.object(logsetup, 'message_handler') as mh_mock:
        with patch('charmcraft.main.Dispatcher.run') as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(['charmcraft', 'version'])

    assert retcode == 33
    assert mh_mock.ended_cmderror.called_once_with(simulated_exception)
Exemple #18
0
def test_main_environment_is_supported_error(
    mock_is_charmcraft_running_in_supported_environment, ):
    mock_is_charmcraft_running_in_supported_environment.return_value = False
    with patch("charmcraft.main.message_handler") as mh_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.return_value = None
            retcode = main(["charmcraft", "version"])

    assert retcode == 1
    assert mh_mock.ended_cmderror.call_count == 1
Exemple #19
0
def test_main_controlled_arguments_error(capsys, base_config_present):
    """The execution failed because an argument parsing error."""
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = ArgumentParsingError("test error")
            retcode = main(["charmcraft", "version"])

    assert retcode == 1
    emit_mock.ended_ok.assert_called_once_with()

    out, err = capsys.readouterr()
    assert not out
    assert err == "test error\n"
Exemple #20
0
def test_main_providing_help(capsys):
    """The execution ended up providing a help message."""
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = ProvideHelpException("nice and shiny help message")
            retcode = main(["charmcraft", "version"])

    assert retcode == 0
    emit_mock.ended_ok.assert_called_once_with()

    out, err = capsys.readouterr()
    assert not out
    assert err == "nice and shiny help message\n"
Exemple #21
0
def test_main_crash():
    """Work crashed: message handler notified properly, return code in 1."""
    simulated_exception = ValueError("boom")
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(["charmcraft", "version"])

    assert retcode == 1
    (call,) = emit_mock.error.mock_calls
    (exc,) = call.args
    assert isinstance(exc, CraftError)
    assert str(exc) == "charmcraft internal error: ValueError('boom')"
    assert exc.__cause__ == simulated_exception
Exemple #22
0
def test_main_interrupted(base_config_present):
    """Work interrupted: message handler notified properly, return code in 1."""
    simulated_exception = KeyboardInterrupt()
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.side_effect = simulated_exception
            retcode = main(["charmcraft", "version"])

    assert retcode == 1
    (call, ) = emit_mock.error.mock_calls
    (exc, ) = call.args
    assert isinstance(exc, CraftError)
    assert str(exc) == "Interrupted."
    assert exc.__cause__ == simulated_exception
Exemple #23
0
def test_main_load_config_not_present_ok():
    """Config is not present but the command does not need it."""
    class MyCommand(BaseCommand):
        help_msg = "some help"
        name = "cmdname"
        overview = "test overview"

        def run(self, parsed_args):
            assert not self.config.project.config_provided

    with patch("charmcraft.main.COMMAND_GROUPS",
               [CommandGroup("title", [MyCommand])]):
        retcode = main(["charmcraft", "cmdname", "--project-dir=/whatever"])
    assert retcode == 0
Exemple #24
0
def test_main_ok():
    """Work ended ok: message handler notified properly, return code in 0."""
    with patch("charmcraft.main.emit") as emit_mock:
        with patch("charmcraft.main.Dispatcher.run") as d_mock:
            d_mock.return_value = None
            retcode = main(["charmcraft", "version"])

    assert retcode == 0
    emit_mock.ended_ok.assert_called_once_with()

    # check how Emitter was initted
    emit_mock.init.assert_called_once_with(
        EmitterMode.NORMAL, "charmcraft", f"Starting charmcraft version {__version__}"
    )
Exemple #25
0
def test_main_load_config_not_present_but_needed(capsys):
    """Command ends indicating the return code to be used."""
    cmd = create_command("cmdname", needs_config_=True)
    with patch("charmcraft.main.COMMAND_GROUPS", [CommandGroup("title", [cmd])]):
        retcode = main(["charmcraft", "cmdname", "--project-dir=/whatever"])
    assert retcode == 1

    out, err = capsys.readouterr()
    assert not out
    assert err == (
        "The specified command needs a valid 'charmcraft.yaml' configuration file (in "
        "the current directory or where specified with --project-dir option); see "
        "the reference: https://discourse.charmhub.io/t/charmcraft-configuration/4138\n"
    )
Exemple #26
0
def test_main_load_config_not_present_ok():
    """Command ends indicating the return code to be used."""

    class MyCommand(BaseCommand):
        help_msg = "some help"
        name = "cmdname"

        def run(self, parsed_args):
            assert self.config.type is None
            assert not self.config.project.config_provided

    with patch("charmcraft.main.COMMAND_GROUPS", [CommandGroup("title", [MyCommand])]):
        retcode = main(["charmcraft", "cmdname", "--project-dir=/whatever"])
    assert retcode == 0
Exemple #27
0
def test_main_load_config_ok(create_config):
    """Command is properly executed, after loading and receiving the config."""
    tmp_path = create_config("""
        type: charm
    """)

    class MyCommand(BaseCommand):
        help_msg = "some help"
        name = "cmdname"
        overview = "test overview"

        def run(self, parsed_args):
            assert self.config.type == "charm"

    with patch("charmcraft.main.COMMAND_GROUPS",
               [CommandGroup("title", [MyCommand])]):
        retcode = main(["charmcraft", "cmdname", f"--project-dir={tmp_path}"])
    assert retcode == 0
Exemple #28
0
def test_main_load_config_not_present_but_needed(capsys):
    """Config is not present and the command needs it."""
    class MyCommand(BaseCommand):
        help_msg = "some help"
        name = "cmdname"
        overview = "test overview"
        needs_config = True

        def run(self, parsed_args):
            pass

    with patch("charmcraft.main.COMMAND_GROUPS",
               [CommandGroup("title", [MyCommand])]):
        retcode = main(["charmcraft", "cmdname", "--project-dir=/whatever"])
    assert retcode == 1

    out, err = capsys.readouterr()
    assert not out
    assert err == (
        "The specified command needs a valid 'charmcraft.yaml' configuration file (in "
        "the current directory or where specified with --project-dir option); see "
        "the reference: https://discourse.charmhub.io/t/charmcraft-configuration/4138\n"
    )
Exemple #29
0
def test_main_no_args():
    """The setup.py entry_point function needs to work with no arguments."""
    with patch("sys.argv", ["charmcraft"]):
        retcode = main()

    assert retcode == 1