Esempio n. 1
0
def test_workflow_plugin_results():
    """
    Verifies the results of plugins in different phases
    are stored properly.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)

    prebuild_plugins = [{'name': 'pre_build_value'}]
    postbuild_plugins = [{'name': 'post_build_value'}]
    prepublish_plugins = [{'name': 'pre_publish_value'}]
    exit_plugins = [{'name': 'exit_value'}]

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=prebuild_plugins,
                                   prepublish_plugins=prepublish_plugins,
                                   postbuild_plugins=postbuild_plugins,
                                   exit_plugins=exit_plugins,
                                   plugin_files=[this_file])

    workflow.build_docker_image()
    assert workflow.prebuild_results == {'pre_build_value': 'pre_build_value_result'}
    assert workflow.postbuild_results == {'post_build_value': 'post_build_value_result'}
    assert workflow.prepub_results == {'pre_publish_value': 'pre_publish_value_result'}
    assert workflow.exit_results == {'exit_value': 'exit_value_result'}
Esempio n. 2
0
def test_workflow_compat(request):
    """
    Some of our plugins have changed from being run post-build to
    being run at exit. Let's test what happens when we try running an
    exit plugin as a post-build plugin.
    """

    this_file = inspect.getfile(PreWatched)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_exit = Watcher()
    fake_logger = FakeLogger()
    existing_logger = atomic_reactor.plugin.logger

    def restore_logger():
        atomic_reactor.plugin.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   postbuild_plugins=[{'name': 'store_logs_to_file',
                                                       'args': {
                                                           'watcher': watch_exit
                                                       }}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()
    assert watch_exit.was_called()
    assert len(fake_logger.errors) > 0
Esempio n. 3
0
def test_layer_sizes():
    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_exit = Watcher()
    watch_buildstep = Watcher()
    workflow = DockerBuildWorkflow(SOURCE, 'test-image',
                                   exit_plugins=[{'name': 'uses_source',
                                                  'args': {
                                                      'watcher': watch_exit,
                                                  }}],
                                   buildstep_plugins=[{'name': 'buildstep_watched',
                                                       'args': {
                                                           'watcher': watch_buildstep,
                                                       }}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()

    expected = [
        {'diff_id': u'sha256:diff_id1-oldest', 'size': 4},
        {'diff_id': u'sha256:diff_id2', 'size': 3},
        {'diff_id': u'sha256:diff_id3', 'size': 2},
        {'diff_id': u'sha256:diff_id4-newest', 'size': 1}
    ]

    assert workflow.layer_sizes == expected
Esempio n. 4
0
def test_plugin_errors(plugins, should_fail, should_log):
    """
    Try bad plugin configuration.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    fake_logger = FakeLogger()
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   plugin_files=[this_file],
                                   **plugins)

    # Find the 'watcher' parameter
    watchers = [conf.get('args', {}).get('watcher')
                for plugin in plugins.values()
                for conf in plugin]
    watcher = [x for x in watchers if x][0]

    if should_fail:
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()

        assert not watcher.was_called()
    else:
        workflow.build_docker_image()
        assert watcher.was_called()

    if should_log:
        assert len(fake_logger.errors) > 0
    else:
        assert len(fake_logger.errors) == 0
def test_build(is_failed, image_id):
    """
    tests docker build api plugin working
    """
    flexmock(DockerfileParser, content='df_content')
    mock_docker()
    fake_builder = MockInsideBuilder(image_id=image_id)
    flexmock(InsideBuilder).new_instances(fake_builder)

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image')
    flexmock(CommandResult).should_receive('is_failed').and_return(is_failed)
    error = "error message"
    error_detail = "{u'message': u\"%s\"}" % error
    if is_failed:
        flexmock(CommandResult, error=error, error_detail=error_detail)
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()
    else:
        workflow.build_docker_image()

    assert isinstance(workflow.buildstep_result['docker_api'], BuildResult)
    assert workflow.build_result == workflow.buildstep_result['docker_api']
    assert workflow.build_result.is_failed() == is_failed

    if is_failed:
        assert workflow.build_result.fail_reason == error
        assert '\\' not in workflow.plugins_errors['docker_api']
        assert error in workflow.plugins_errors['docker_api']
    else:
        assert workflow.build_result.image_id.startswith('sha256:')
        assert workflow.build_result.image_id.count(':') == 1
Esempio n. 6
0
def test_autorebuild_stop_prevents_build():
    """
    test that a plugin that raises AutoRebuildCanceledException results in actually skipped build
    """
    this_file = inspect.getfile(PreWatched)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    workflow = DockerBuildWorkflow(
        MOCK_SOURCE,
        "test-image",
        prebuild_plugins=[{"name": "stopstopstop", "args": {}}],
        prepublish_plugins=[{"name": "prepub_watched", "args": {"watcher": watch_prepub}}],
        postbuild_plugins=[{"name": "post_watched", "args": {"watcher": watch_post}}],
        exit_plugins=[{"name": "exit_watched", "args": {"watcher": watch_exit}}],
        plugin_files=[this_file],
    )

    with pytest.raises(AutoRebuildCanceledException):
        workflow.build_docker_image()

    assert not watch_prepub.was_called()
    assert not watch_post.was_called()
    assert watch_exit.was_called()
    assert workflow.autorebuild_canceled == True
Esempio n. 7
0
def test_workflow():
    """
    Test normal workflow.
    """

    this_file = inspect.getfile(PreWatched)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    workflow = DockerBuildWorkflow(
        MOCK_SOURCE,
        "test-image",
        prebuild_plugins=[{"name": "pre_watched", "args": {"watcher": watch_pre}}],
        prepublish_plugins=[{"name": "prepub_watched", "args": {"watcher": watch_prepub}}],
        postbuild_plugins=[{"name": "post_watched", "args": {"watcher": watch_post}}],
        exit_plugins=[{"name": "exit_watched", "args": {"watcher": watch_exit}}],
        plugin_files=[this_file],
    )

    workflow.build_docker_image()

    assert watch_pre.was_called()
    assert watch_prepub.was_called()
    assert watch_post.was_called()
    assert watch_exit.was_called()
def test_syntax_error():
    """
    tests reporting of syntax errors
    """
    flexmock(DockerfileParser, content='df_content')
    mock_docker()
    fake_builder = MockInsideBuilder()

    def raise_exc(*args, **kwargs):
        explanation = ("Syntax error - can't find = in \"CMD\". "
                       "Must be of the form: name=value")
        http_error = requests.HTTPError('500 Server Error')
        raise docker.errors.APIError(message='foo',
                                     response=http_error,
                                     explanation=explanation)
        yield {}

    fake_builder.tasker.build_image_from_path = raise_exc
    flexmock(InsideBuilder).new_instances(fake_builder)
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image')
    with pytest.raises(PluginFailedException):
        workflow.build_docker_image()

    assert isinstance(workflow.buildstep_result['docker_api'], BuildResult)
    assert workflow.build_result == workflow.buildstep_result['docker_api']
    assert workflow.build_result.is_failed()
    assert "Syntax error" in workflow.build_result.fail_reason
Esempio n. 9
0
def test_workflow_docker_build_error_reports(steps_to_fail, step_reported):
    """
    Test if first error is reported properly. (i.e. exit plugins are not
    hiding the original root cause)
    """
    def exc_string(step):
        return 'test_workflow_docker_build_error_reports.{}'.format(step)

    def construct_watcher(step):
        watcher = Watcher(raise_exc=Exception(exc_string(step)) if step in steps_to_fail else None)
        return watcher

    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder(failed=True)
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = construct_watcher('pre')
    watch_buildstep = construct_watcher('buildstep')
    watch_prepub = construct_watcher('prepub')
    watch_post = construct_watcher('post')
    watch_exit = construct_watcher('exit')

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'is_allowed_to_fail': False,
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   buildstep_plugins=[{'name': 'buildstep_watched',
                                                       'is_allowed_to_fail': False,
                                                       'args': {
                                                           'watcher': watch_buildstep,
                                                       }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'is_allowed_to_fail': False,
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'is_allowed_to_fail': False,
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'is_allowed_to_fail': False,
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    with pytest.raises(Exception) as exc:
        workflow.build_docker_image()
    assert exc_string(step_reported) in str(exc)
Esempio n. 10
0
def test_plugin_errors(request, plugins, should_fail, should_log):
    """
    Try bad plugin configuration.
    """
    flexmock(DockerfileParser, content='df_content')
    flexmock(DockerApiPlugin).should_receive('run').and_return(DUMMY_BUILD_RESULT)
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    fake_logger = FakeLogger()

    existing_logger = atomic_reactor.plugin.logger

    def restore_logger():
        atomic_reactor.plugin.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   plugin_files=[this_file],
                                   **plugins)

    # Find the 'watcher' parameter
    watchers = [conf.get('args', {}).get('watcher')
                for plugin in plugins.values()
                for conf in plugin]
    watcher = [x for x in watchers if x][0]

    if should_fail:
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()

        assert not watcher.was_called()
        assert workflow.plugins_errors
        assert all([is_string_type(plugin)
                    for plugin in workflow.plugins_errors])
        assert all([is_string_type(reason)
                    for reason in workflow.plugins_errors.values()])
    else:
        workflow.build_docker_image()
        assert watcher.was_called()
        assert not workflow.plugins_errors

    if should_log:
        assert len(fake_logger.errors) > 0
    else:
        assert len(fake_logger.errors) == 0
Esempio n. 11
0
def test_workflow_errors():
    """
    This is a test for what happens when plugins fail.

    When a prebuild plugin fails, no postbuild plugins should run.
    However, all the exit plugins should run.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_raises',
                                                      'args': {}},
                                                     {'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_raises',
                                                  'args': {}
                                                  },
                                                 {'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    with pytest.raises(PluginFailedException):
        workflow.build_docker_image()

    # A pre-build plugin caused the build to fail, so post-build
    # plugins should not run.
    assert not watch_post.was_called()

    # But all exit plugins should run, even if one of them also raises
    # an exception.
    assert watch_exit.was_called()

    # All plugins of the same type (e.g. pre-build) are run, even if
    # one of them failed.
    assert watch_pre.was_called()
Esempio n. 12
0
def test_workflow_base_images():
    """
    Test workflow for base images
    """

    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreWatched)
    mock_docker()
    fake_builder = MockInsideBuilder(is_base_image=True)
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_prepub = Watcher()
    watch_buildstep = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   buildstep_plugins=[{'name': 'buildstep_watched',
                                                       'args': {
                                                           'watcher': watch_buildstep
                                                       }}],

                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()

    assert watch_pre.was_called()
    assert watch_prepub.was_called()
    assert watch_buildstep.was_called()
    assert watch_post.was_called()
    assert watch_exit.was_called()
    with pytest.raises(KeyError):
        assert workflow.base_image_inspect
Esempio n. 13
0
def test_workflow_docker_build_error():
    """
    This is a test for what happens when the docker build fails.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder(failed=True)
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    assert workflow.build_docker_image().is_failed()

    # No subsequent build phases should have run except 'exit'
    assert not watch_prepub.was_called()
    assert not watch_post.was_called()
    assert watch_exit.was_called()
Esempio n. 14
0
def build_image_here(source, image,
        parent_registry=None, target_registries=None, parent_registry_insecure=False,
        target_registries_insecure=False, dont_pull_base_image=False, **kwargs):
    """
    build image from provided dockerfile (specified by `source`) in current environment

    :param source: dict, where/how to get source code to put in image
    :param image: str, tag for built image ([registry/]image_name[:tag])
    :param parent_registry: str, registry to pull base image from
    :param target_registries: list of str, list of registries to push image to (might change in future)
    :param parent_registry_insecure: bool, allow connecting to parent registry over plain http
    :param target_registries_insecure: bool, allow connecting to target registries over plain http
    :param dont_pull_base_image: bool, don't pull or update base image specified in dockerfile

    :return: BuildResults
    """
    build_json = {
        "image": image,
        "source": source,
        "parent_registry": parent_registry,
        "target_registries": target_registries,
        "parent_registry_insecure": parent_registry_insecure,
        "target_registries_insecure": target_registries_insecure,
        "dont_pull_base_image": dont_pull_base_image,
    }
    build_json.update(kwargs)
    m = DockerBuildWorkflow(**build_json)
    return m.build_docker_image()
Esempio n. 15
0
def test_source_not_removed_for_exit_plugins():
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_exit = Watcher()
    workflow = DockerBuildWorkflow(SOURCE, 'test-image',
                                   exit_plugins=[{'name': 'uses_source',
                                                  'args': {
                                                      'watcher': watch_exit,
                                                  }}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()

    # Make sure that the plugin was actually run
    assert watch_exit.was_called()
Esempio n. 16
0
def test_workflow_docker_build_error():
    """
    This is a test for what happens when the docker build fails.
    """
    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder(failed=True)
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_buildstep = Watcher(raise_exc=Exception())
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   buildstep_plugins=[{'name': 'buildstep_watched',
                                                       'args': {
                                                           'watcher': watch_buildstep,
                                                       }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    with pytest.raises(Exception):
        workflow.build_docker_image()
    # No subsequent build phases should have run except 'exit'
    assert watch_pre.was_called()
    assert watch_buildstep.was_called()
    assert not watch_prepub.was_called()
    assert not watch_post.was_called()
    assert watch_exit.was_called()
Esempio n. 17
0
def test_workflow_plugin_results(buildstep_plugin, buildstep_raises):
    """
    Verifies the results of plugins in different phases
    are stored properly.
    It also verifies failed and remote BuildResult is handled properly.
    """

    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)

    prebuild_plugins = [{'name': 'pre_build_value'}]
    buildstep_plugins = [{'name': buildstep_plugin}]
    postbuild_plugins = [{'name': 'post_build_value'}]
    prepublish_plugins = [{'name': 'pre_publish_value'}]
    exit_plugins = [{'name': 'exit_value'}]

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=prebuild_plugins,
                                   buildstep_plugins=buildstep_plugins,
                                   prepublish_plugins=prepublish_plugins,
                                   postbuild_plugins=postbuild_plugins,
                                   exit_plugins=exit_plugins,
                                   plugin_files=[this_file])

    if buildstep_raises:
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()
    else:
        workflow.build_docker_image()

    assert workflow.prebuild_results == {'pre_build_value': 'pre_build_value_result'}
    assert isinstance(workflow.buildstep_result[buildstep_plugin], BuildResult)

    if buildstep_raises:
        assert workflow.postbuild_results == {}
        assert workflow.prepub_results == {}
    else:
        assert workflow.postbuild_results == {'post_build_value': 'post_build_value_result'}
        assert workflow.prepub_results == {'pre_publish_value': 'pre_publish_value_result'}

    assert workflow.exit_results == {'exit_value': 'exit_value_result'}
Esempio n. 18
0
def test_show_version(request, has_version):
    """
    Test atomic-reactor print version of osbs-client used to build the build json
    if available
    """
    VERSION = "1.0"
    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)

    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)

    watch_buildstep = Watcher()
    fake_logger = FakeLogger()
    existing_logger = atomic_reactor.inner.logger

    def restore_logger():
        atomic_reactor.inner.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.inner.logger = fake_logger

    params = {
        'prebuild_plugins': [],
        'buildstep_plugins': [{'name': 'buildstep_watched',
                               'args': {'watcher': watch_buildstep}}],
        'prepublish_plugins': [],
        'postbuild_plugins': [],
        'exit_plugins': [],
        'plugin_files': [this_file],
    }
    if has_version:
        params['client_version'] = VERSION

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image', **params)
    workflow.build_docker_image()
    expected_log_message = ("build json was built by osbs-client %s", VERSION)
    assert (expected_log_message in fake_logger.debugs) == has_version
Esempio n. 19
0
def test_workflow():
    """
    Test normal workflow.
    """

    this_file = inspect.getfile(PreWatched)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()

    assert watch_pre.was_called()
    assert watch_prepub.was_called()
    assert watch_post.was_called()
    assert watch_exit.was_called()
Esempio n. 20
0
def test_workflow_compat():
    """
    Some of our plugins have changed from being run post-build to
    being run at exit. Let's test what happens when we try running an
    exit plugin as a post-build plugin.
    """

    this_file = inspect.getfile(PreWatched)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_exit = Watcher()
    fake_logger = FakeLogger()
    atomic_reactor.plugin.logger = fake_logger
    workflow = DockerBuildWorkflow(
        MOCK_SOURCE,
        "test-image",
        postbuild_plugins=[{"name": "store_logs_to_file", "args": {"watcher": watch_exit}}],
        plugin_files=[this_file],
    )

    workflow.build_docker_image()
    assert watch_exit.was_called()
    assert len(fake_logger.errors) > 0
Esempio n. 21
0
def test_plugin_errors():
    """
    Try bad plugin configuration.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    fake_logger = FakeLogger()
    atomic_reactor.plugin.logger = fake_logger

    # No 'name' key
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'args': {}}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()
    assert len(fake_logger.errors) > 0

    # No 'args' key
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre'}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()
    assert len(fake_logger.errors) > 0

    # No such plugin
    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'no plugin',
                                                      'args': {}}],
                                   plugin_files=[this_file])

    workflow.build_docker_image()
    assert len(fake_logger.errors) > 0
Esempio n. 22
0
def test_cancel_build(request, fail_at):
    """
    Verifies that exit plugins are executed when the build is canceled
    """

    # Make the phase we're testing send us SIGTERM
    phase_signal = defaultdict(lambda: None)
    phase_signal[fail_at] = signal.SIGTERM

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    build_timeout = 10 if fail_at == 'build' else 0
    sigterm_timeout = 2
    fake_builder = MockInsideBuilder(timeout=build_timeout)
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = WatcherWithSignal(phase_signal['pre'])
    watch_prepub = WatcherWithSignal(phase_signal['prepub'])
    watch_post = WatcherWithSignal(phase_signal['post'])
    watch_exit = WatcherWithSignal(phase_signal['exit'])

    fake_logger = FakeLogger()
    existing_logger = atomic_reactor.plugin.logger

    def restore_logger():
        atomic_reactor.plugin.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    if fail_at == 'build':
        pid = os.getpid()
        thread = threading.Thread(
            target=lambda: (
                sleep(sigterm_timeout),
                os.kill(pid, signal.SIGTERM)))
        thread.start()

        with pytest.raises(BuildCanceledException):
            workflow.build_docker_image()
    else:
        workflow.build_docker_image()

    if fail_at not in ['exit', 'build']:
        assert ("plugin '%s_watched' raised an exception:" % fail_at +
                " BuildCanceledException('Build was canceled',)",) in fake_logger.warnings

    assert watch_exit.was_called()
    assert watch_pre.was_called()

    if fail_at not in ['pre', 'build']:
        assert watch_prepub.was_called()

    if fail_at not in ['pre', 'prepub', 'build']:
        assert watch_post.was_called()
Esempio n. 23
0
def test_cancel_build(request, fail_at):
    """
    Verifies that exit plugins are executed when the build is canceled
    """
    # Make the phase we're testing send us SIGTERM
    phase_signal = defaultdict(lambda: None)
    phase_signal[fail_at] = signal.SIGTERM
    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = WatcherWithSignal(phase_signal['pre'])
    watch_prepub = WatcherWithSignal(phase_signal['prepub'])
    watch_buildstep = WatcherWithSignal(phase_signal['buildstep'])
    watch_post = WatcherWithSignal(phase_signal['post'])
    watch_exit = WatcherWithSignal(phase_signal['exit'])

    fake_logger = FakeLogger()
    existing_logger = atomic_reactor.plugin.logger

    def restore_logger():
        atomic_reactor.plugin.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   buildstep_plugins=[{'name': 'buildstep_watched',
                                                       'args': {
                                                           'watcher': watch_buildstep
                                                       }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])
    if fail_at == 'buildstep':
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()
        assert ("plugin '%s_watched' raised an exception:" % fail_at +
                " BuildCanceledException('Build was canceled',)",) in fake_logger.errors
    else:
        workflow.build_docker_image()

        if fail_at != 'exit':
            assert ("plugin '%s_watched' raised an exception:" % fail_at +
                    " BuildCanceledException('Build was canceled',)",) in fake_logger.warnings

    assert watch_exit.was_called()
    assert watch_pre.was_called()

    if fail_at not in ['pre', 'buildstep']:
        assert watch_prepub.was_called()

    if fail_at not in ['pre', 'prepub', 'buildstep']:
        assert watch_post.was_called()
Esempio n. 24
0
def test_workflow_plugin_error(fail_at):
    """
    This is a test for what happens when plugins fail.

    When a prebuild or postbuild plugin fails, and doesn't have
    is_allowed_to_fail=True set, the whole build should fail.
    However, all the exit plugins should run.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    prebuild_plugins = [{'name': 'pre_watched',
                         'args': {
                             'watcher': watch_pre,
                         }}]
    prepublish_plugins = [{'name': 'prepub_watched',
                           'args': {
                               'watcher': watch_prepub,
                           }}]
    postbuild_plugins = [{'name': 'post_watched',
                          'args': {
                              'watcher': watch_post
                          }}]
    exit_plugins = [{'name': 'exit_watched',
                     'args': {
                         'watcher': watch_exit
                     }}]

    # Insert a failing plugin into one of the build phases
    if fail_at == 'pre':
        prebuild_plugins.insert(0, {'name': 'pre_raises', 'args': {}})
    elif fail_at == 'prepub':
        prepublish_plugins.insert(0, {'name': 'prepub_raises', 'args': {}})
    elif fail_at == 'post':
        postbuild_plugins.insert(0, {'name': 'post_raises', 'args': {}})
    elif fail_at == 'exit':
        exit_plugins.insert(0, {'name': 'exit_raises', 'args': {}})
    else:
        # Typo in the parameter list?
        assert False

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=prebuild_plugins,
                                   prepublish_plugins=prepublish_plugins,
                                   postbuild_plugins=postbuild_plugins,
                                   exit_plugins=exit_plugins,
                                   plugin_files=[this_file])

    # Failures in any phase except 'exit' cause the build process to
    # abort.
    if fail_at == 'exit':
        build_result = workflow.build_docker_image()
        assert build_result and not build_result.is_failed()
    else:
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()

    # The pre-build phase should only complete if there were no
    # earlier plugin failures.
    assert watch_pre.was_called() == (fail_at != 'pre')

    # The prepublish phase should only complete if there were no
    # earlier plugin failures.
    assert watch_prepub.was_called() == (fail_at not in ('pre', 'prepub'))

    # The post-build phase should only complete if there were no
    # earlier plugin failures.
    assert watch_post.was_called() == (fail_at not in ('pre', 'prepub', 'post'))

    # But all exit plugins should run, even if one of them also raises
    # an exception.
    assert watch_exit.was_called()
Esempio n. 25
0
def test_workflow_plugin_error(fail_at):
    """
    This is a test for what happens when plugins fail.

    When a prebuild or postbuild plugin fails, and doesn't have
    is_allowed_to_fail=True set, the whole build should fail.
    However, all the exit plugins should run.
    """
    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_prepub = Watcher()
    watch_buildstep = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    prebuild_plugins = [{'name': 'pre_watched',
                         'args': {
                             'watcher': watch_pre,
                         }}]
    buildstep_plugins = [{'name': 'buildstep_watched',
                          'args': {
                              'watcher': watch_buildstep,
                          }}]
    prepublish_plugins = [{'name': 'prepub_watched',
                           'args': {
                               'watcher': watch_prepub,
                           }}]
    postbuild_plugins = [{'name': 'post_watched',
                          'args': {
                              'watcher': watch_post
                          }}]
    exit_plugins = [{'name': 'exit_watched',
                     'args': {
                         'watcher': watch_exit
                     }}]

    # Insert a failing plugin into one of the build phases
    if fail_at == 'pre_raises':
        prebuild_plugins.insert(0, {'name': fail_at, 'args': {}})
    elif fail_at == 'buildstep_raises':
        buildstep_plugins.insert(0, {'name': fail_at, 'args': {}})
    elif fail_at == 'prepub_raises':
        prepublish_plugins.insert(0, {'name': fail_at, 'args': {}})
    elif fail_at == 'post_raises':
        postbuild_plugins.insert(0, {'name': fail_at, 'args': {}})
    elif fail_at == 'exit_raises' or fail_at == 'exit_raises_allowed':
        exit_plugins.insert(0, {'name': fail_at, 'args': {}})
    else:
        # Typo in the parameter list?
        assert False

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=prebuild_plugins,
                                   buildstep_plugins=buildstep_plugins,
                                   prepublish_plugins=prepublish_plugins,
                                   postbuild_plugins=postbuild_plugins,
                                   exit_plugins=exit_plugins,
                                   plugin_files=[this_file])

    # Most failures cause the build process to abort. Unless, it's
    # an exit plugin that's explicitly allowed to fail.
    if fail_at == 'exit_raises_allowed':
        workflow.build_docker_image()
        assert not workflow.plugins_errors
    else:
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()

        assert fail_at in workflow.plugins_errors

    # The pre-build phase should only complete if there were no
    # earlier plugin failures.
    assert watch_pre.was_called() == (fail_at != 'pre_raises')

    # The buildstep phase should only complete if there were no
    # earlier plugin failures.
    assert watch_buildstep.was_called() == (fail_at not in ('pre_raises',
                                                            'buildstep_raises'))

    # The prepublish phase should only complete if there were no
    # earlier plugin failures.
    assert watch_prepub.was_called() == (fail_at not in ('pre_raises',
                                                         'prepub_raises',
                                                         'buildstep_raises'))

    # The post-build phase should only complete if there were no
    # earlier plugin failures.
    assert watch_post.was_called() == (fail_at not in ('pre_raises',
                                                       'prepub_raises',
                                                       'buildstep_raises',
                                                       'post_raises'))

    # But all exit plugins should run, even if one of them also raises
    # an exception.
    assert watch_exit.was_called()
Esempio n. 26
0
def test_workflow_plugin_error(fail_at):
    """
    This is a test for what happens when plugins fail.

    When a prebuild or postbuild plugin fails, and doesn't have
    is_allowed_to_fail=True set, the whole build should fail.
    However, all the exit plugins should run.
    """

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = Watcher()
    watch_prepub = Watcher()
    watch_post = Watcher()
    watch_exit = Watcher()
    prebuild_plugins = [{"name": "pre_watched", "args": {"watcher": watch_pre}}]
    prepublish_plugins = [{"name": "prepub_watched", "args": {"watcher": watch_prepub}}]
    postbuild_plugins = [{"name": "post_watched", "args": {"watcher": watch_post}}]
    exit_plugins = [{"name": "exit_watched", "args": {"watcher": watch_exit}}]

    # Insert a failing plugin into one of the build phases
    if fail_at == "pre":
        prebuild_plugins.insert(0, {"name": "pre_raises", "args": {}})
    elif fail_at == "prepub":
        prepublish_plugins.insert(0, {"name": "prepub_raises", "args": {}})
    elif fail_at == "post":
        postbuild_plugins.insert(0, {"name": "post_raises", "args": {}})
    elif fail_at == "exit":
        exit_plugins.insert(0, {"name": "exit_raises", "args": {}})
    else:
        # Typo in the parameter list?
        assert False

    workflow = DockerBuildWorkflow(
        MOCK_SOURCE,
        "test-image",
        prebuild_plugins=prebuild_plugins,
        prepublish_plugins=prepublish_plugins,
        postbuild_plugins=postbuild_plugins,
        exit_plugins=exit_plugins,
        plugin_files=[this_file],
    )

    # Failures in any phase except 'exit' cause the build process to
    # abort.
    if fail_at == "exit":
        workflow.build_docker_image()
    else:
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()

    # The pre-build phase should only complete if there were no
    # earlier plugin failures.
    assert watch_pre.was_called() == (fail_at != "pre")

    # The prepublish phase should only complete if there were no
    # earlier plugin failures.
    assert watch_prepub.was_called() == (fail_at not in ("pre", "prepub"))

    # The post-build phase should only complete if there were no
    # earlier plugin failures.
    assert watch_post.was_called() == (fail_at not in ("pre", "prepub", "post"))

    # But all exit plugins should run, even if one of them also raises
    # an exception.
    assert watch_exit.was_called()
Esempio n. 27
0
def test_cancel_build(request, fail_at):
    """
    Verifies that exit plugins are executed when the build is canceled
    """
    # Make the phase we're testing send us SIGTERM
    phase_signal = defaultdict(lambda: None)
    phase_signal[fail_at] = signal.SIGTERM
    flexmock(DockerfileParser, content='df_content')
    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder()
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = WatcherWithSignal(phase_signal['pre'])
    watch_prepub = WatcherWithSignal(phase_signal['prepub'])
    watch_buildstep = WatcherWithSignal(phase_signal['buildstep'])
    watch_post = WatcherWithSignal(phase_signal['post'])
    watch_exit = WatcherWithSignal(phase_signal['exit'])

    fake_logger = FakeLogger()
    existing_logger = atomic_reactor.plugin.logger

    def restore_logger():
        atomic_reactor.plugin.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   buildstep_plugins=[{'name': 'buildstep_watched',
                                                       'args': {
                                                           'watcher': watch_buildstep
                                                       }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])
    # BaseException repr does not include trailing comma in Python >= 3.7
    # we look for a partial match in log strings for Python < 3.7 compatibility
    expected_entry = (
        "plugin '{}_watched' raised an exception: BuildCanceledException('Build was canceled'"
    )
    if fail_at == 'buildstep':
        with pytest.raises(PluginFailedException):
            workflow.build_docker_image()
        assert workflow.build_canceled
        assert any(expected_entry.format(fail_at) in entry[0] for entry in fake_logger.errors)
    else:
        workflow.build_docker_image()

        if fail_at != 'exit':
            assert workflow.build_canceled
            assert any(expected_entry.format(fail_at) in entry[0] for entry in fake_logger.warnings)
        else:
            assert not workflow.build_canceled

    assert watch_exit.was_called()
    assert watch_pre.was_called()

    if fail_at not in ['pre', 'buildstep']:
        assert watch_prepub.was_called()

    if fail_at not in ['pre', 'prepub', 'buildstep']:
        assert watch_post.was_called()
Esempio n. 28
0
def test_cancel_build(request, fail_at):
    """
    Verifies that exit plugins are executed when the build is canceled
    """
    phase_duration = 10
    sigterm_timeout = 2

    phase_timeout = {'pre': 0, 'prepub': 0, 'build': 0, 'post': 0, 'exit': 0}
    phase_timeout[fail_at] = phase_duration

    this_file = inspect.getfile(PreRaises)
    mock_docker()
    fake_builder = MockInsideBuilder(timeout=phase_timeout['build'])
    flexmock(InsideBuilder).new_instances(fake_builder)
    watch_pre = WatcherWithPause(phase_timeout['pre'])
    watch_prepub = WatcherWithPause(phase_timeout['prepub'])
    watch_post = WatcherWithPause(phase_timeout['post'])
    watch_exit = WatcherWithPause(phase_timeout['exit'])

    fake_logger = FakeLogger()
    existing_logger = atomic_reactor.plugin.logger

    def restore_logger():
        atomic_reactor.plugin.logger = existing_logger

    request.addfinalizer(restore_logger)
    atomic_reactor.plugin.logger = fake_logger

    workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image',
                                   prebuild_plugins=[{'name': 'pre_watched',
                                                      'args': {
                                                          'watcher': watch_pre
                                                      }}],
                                   prepublish_plugins=[{'name': 'prepub_watched',
                                                        'args': {
                                                            'watcher': watch_prepub,
                                                        }}],
                                   postbuild_plugins=[{'name': 'post_watched',
                                                       'args': {
                                                           'watcher': watch_post
                                                       }}],
                                   exit_plugins=[{'name': 'exit_watched',
                                                  'args': {
                                                      'watcher': watch_exit
                                                  }}],
                                   plugin_files=[this_file])

    pid = os.getpid()
    thread = threading.Thread(
        target=lambda: (
            sleep(sigterm_timeout),
            os.kill(pid, signal.SIGTERM)))
    thread.start()

    if fail_at == 'build':
        with pytest.raises(BuildCanceledException):
            workflow.build_docker_image()
    else:
        workflow.build_docker_image()

    if fail_at not in ['exit', 'build']:
        assert ("plugin '%s_watched' raised an exception:" % fail_at +
                " BuildCanceledException('Build was canceled',)",) in fake_logger.warnings

    assert watch_exit.was_called()
    assert watch_pre.was_called()

    if fail_at not in ['pre', 'build']:
        assert watch_prepub.was_called()

    if fail_at not in ['pre', 'prepub', 'build']:
        assert watch_post.was_called()