Ejemplo n.º 1
0
def test_render_section_invalid_template():
    template_string = """
        {% for %}
        """

    state = {"foo": 2}
    section = {"template": template_string}

    with pytest.raises(ValidationError):
        parsing.render_section(section, state=state)
Ejemplo n.º 2
0
def test_render_section_dict_no_template():
    section = {"foo": "{{ state['bar'] }}", "fizz": "{{ json.loads('true') }}"}
    state = {"bar": 24}

    rendered_section = parsing.render_section(section, state=state)

    assert rendered_section == {"foo": 24, "fizz": True}
Ejemplo n.º 3
0
def test_render_section_string():
    template_string = "{{ state['foo'] }}"
    state = {"foo": 24}

    rendered_section = parsing.render_section(template_string, state=state)

    assert rendered_section == 24
Ejemplo n.º 4
0
def run_asserts(asserts: List[Assert], state: dict, hostname: str,
                seconds_between_asserts: float) -> Statuses:
    """
    Run asserts assigned to host

    Args:
        asserts: List of asserts assigned to host
        state: Test state to pass to templates
        hostname: Host name to send assert data to
        seconds_between_asserts: Time to wait in between running each assert

    Returns:
        Statuses of all asserts run by host
    """
    results: Statuses = {}

    for i, asrt in enumerate(asserts):
        rendered_assert: Assert = render_section(asrt, state)

        assert_name = rendered_assert.get("name")
        executions_per_cycle = rendered_assert.get("executionsPerCycle", 1)
        assert_results: List[AssertResult] = []

        if rendered_assert["type"] == "NullAssert":
            for _ in range(executions_per_cycle):
                # NOTE: possibly add template free way of computing passed
                assert_results.append(
                    AssertResult(
                        passed=rendered_assert.get("passed", False),
                        actual=rendered_assert.get("actual", ""),
                        expected=rendered_assert.get("expected", ""),
                        description=rendered_assert.get("description", ""),
                    ))
        else:
            assert ("params" in rendered_assert
                    ), f"Assert {assert_name} is missing property 'params'"

            for _ in range(executions_per_cycle):
                assert_results.append(send_assert(hostname, rendered_assert))

        save_assert_versions = rendered_assert.get("storeVersions", True)

        if not save_assert_versions:
            results[assert_name] = assert_results[-1]
        else:
            results[assert_name] = assert_results

        if i != len(asserts) - 1:
            # Only wait if there is another assert
            time.sleep(seconds_between_asserts)

    return results
Ejemplo n.º 5
0
def test_render_section_kwargs():
    template_string = """
        params:
            value: {{ state['foo'] + results['bar'] }}
        """

    state = {"foo": 2}
    results = {"bar": 4}
    section = {"template": template_string}

    rendered_section = parsing.render_section(section,
                                              state=state,
                                              results=results)
    assert rendered_section["params"]["value"] == 6
Ejemplo n.º 6
0
def test_render_section_multiple_parts():
    template_string = """
        image: {{ state['foo'] }}
        volumes:
          - name: {{ state['bar'] }}
            path: bar
    """

    section = {"name": "some name", "template": template_string}
    state = {"foo": "fizz", "bar": "buzz"}

    rendered_section = parsing.render_section(section, state=state)

    assert rendered_section["image"] == "fizz"
    assert rendered_section["volumes"][0]["name"] == "buzz"
Ejemplo n.º 7
0
def test_render_section():
    template_string = """
        params:
            {% set ids = [] %}
            {% for member in state['add_members']['actions']['POST0']['results'] %}
            {% do ids.append(member['body']['id']) %}
            {% endfor %}
            query: "update members set name='jeff2' where id in ({{ ids|join(',') }})"
        """

    section = {"type": "SQLQuery", "template": template_string}

    state = {
        "add_members": {
            "actions": {
                "POST0": {
                    "results": [
                        {
                            "body": {
                                "id": 1
                            }
                        },
                        {
                            "body": {
                                "id": 2
                            }
                        },
                    ]
                }
            }
        }
    }

    rendered_section = parsing.render_section(section, state=state)

    assert rendered_section["type"] == "SQLQuery"
    assert rendered_section["params"] == {
        "query": "update members set name='jeff2' where id in (1,2)"
    }
Ejemplo n.º 8
0
def test_render_section_not_found():
    section = {"foo": "{{ bar }}"}

    rendered_section = parsing.render_section(section, state={})

    assert rendered_section == {"foo": None}
Ejemplo n.º 9
0
    def closure(state):
        try:
            rendered_test_config: TestConfig = render_section(
                test_config, state)

            image = runner_to_image(rendered_test_config.get(
                "runner")) or rendered_test_config.get("image")

            assert image is not None, "Must specify a valid 'runner' or 'image'"

            env = config_to_runner_env(
                render_section(rendered_test_config.get("config", {}), state))

            runners = []

            for _ in range(rendered_test_config.get("runnerCount", 1)):
                runner = create_runner_fn(
                    image,
                    env,
                    run_id,
                    volumes=rendered_test_config.get("volumes"))
                runners.append(runner)

            try:
                new_state = run_test_with_timeout(
                    test_config=rendered_test_config,
                    incoming_state=state,
                    hostnames=[
                        get_runner_hostname_fn(runner) for runner in runners
                    ],
                    duration=rendered_test_config.get("timeout", 15),
                )
            except (AssertionError, ValueError, TypeError,
                    RuntimeError) as err:
                # NOTE: May need to fine tune exception types
                LOGGER.error("Error running test %s: %s",
                             test_config["name"],
                             err,
                             exc_info=True)

                for runner in runners:
                    remove_runner_fn(runner)

                new_state = {
                    test_config["name"]: {
                        "summary":
                        TestSummary(
                            description=rendered_test_config.get(
                                "description"),
                            error=str(err),
                            completed_cycles=0,
                            remaining_asserts=[],
                            duration=0,
                            filename=rendered_test_config.get("filename"),
                        )
                    }
                }

            for runner in runners:
                remove_runner_fn(runner)
        except (AssertionError, ValueError, TypeError, RuntimeError) as err:
            LOGGER.error("Error creating test %s: %s",
                         test_config["name"],
                         err,
                         exc_info=True)

            new_state = {
                test_config["name"]: {
                    "summary":
                    TestSummary(
                        description=test_config.get("description"),
                        error=str(err),
                        completed_cycles=0,
                        remaining_asserts=[],
                        duration=0,
                        filename=test_config.get("filename"),
                    )
                }
            }

        return {**state, **new_state}
Ejemplo n.º 10
0
def run_actions(
    actions: List[Action], state: dict, hostname: str, seconds_between_actions: float
) -> ActionsData:
    """
    Runs a list of actions assigned to a single runner

    Args:
        actions: List of actions to run
        state: Incoming state to use in rendering actions
        hostname: Address of runner
        seconds_between_actions: Seconds to wait between running next action in list

    Returns:
        ActionsData per action provided
    """

    def infinite_defaultdict():
        return defaultdict(infinite_defaultdict)

    data: ActionsData = OrderedDict(
        (action["name"], infinite_defaultdict()) for action in actions
    )

    with get_action_sender(hostname) as send_action:
        for i, action in enumerate(actions):
            rendered_action: Action = render_section(action, state)

            action_name = rendered_action["name"]

            assert (
                "params" in rendered_action
            ), f"Action {action_name} is missing property 'params'"

            executions_per_cycle: int = rendered_action.get("executionsPerCycle", 1)
            action_results: List[ActionResult] = []
            # assert_results: Statuses = defaultdict(list)
            assert_results: Statuses = OrderedDict(
                (asrt["name"], []) for asrt in rendered_action.get("asserts", [])
            )

            for _ in range(executions_per_cycle):
                execution_output: ActionResult = send_action(rendered_action)
                action_results.append(execution_output)

                for asrt in get_remaining_asserts(
                    rendered_action.get("asserts", []), assert_results
                ):
                    rendered_assert: Assert = render_section(
                        section=asrt, state=state, result=execution_output
                    )

                    assert_name = asrt["name"]
                    store_assert_versions = rendered_assert.get("storeVersions", True)
                    assert_result = run_assert_from_action_result(
                        rendered_assert, execution_output
                    )

                    if store_assert_versions:
                        assert_results[assert_name].append(assert_result)
                    else:
                        assert_results[assert_name] = assert_result

                time.sleep(rendered_action.get("secondsBetweenExecutions", 0))

            store_action_versions = rendered_action.get("storeVersions", True)

            if not store_action_versions and action_results:
                data[action_name]["results"] = action_results[-1]
            else:
                data[action_name]["results"] = action_results

            data[action_name]["asserts"] = assert_results

            for output in rendered_action.get("outputs", []):
                rendered_output: Output = render_section(
                    section=output, state=state, results=action_results
                )

                assert (
                    "name" in rendered_output
                ), "Output section must have parameter 'name'"
                assert (
                    "value" in rendered_output
                ), "Output section must have parameter 'value'"

                # NOTE: support updating outputs in globals section?
                store_output_versions = rendered_output.get("storeVersions", False)

                if not store_output_versions:
                    data[action_name]["outputs"][
                        rendered_output["name"]
                    ] = rendered_output["value"]
                else:
                    data[action_name]["outputs"][rendered_output["name"]] = [
                        rendered_output["value"]
                    ]

            if i != len(actions) - 1:
                # Only wait if there is another action
                time.sleep(seconds_between_actions)

    return data
Ejemplo n.º 11
0
    def closure(state):
        try:
            # TODO: break out docker specific sections
            rendered_test_config = render_section(test_config, state)

            image = runner_to_image(rendered_test_config.get(
                "runner")) or rendered_test_config.get("image")

            assert image is not None, "Must specify a valid 'runner' or 'image'"

            env = config_to_runner_env(
                render_section(rendered_test_config.get("config", {}), state))

            # NOTE: client may need more config options
            client: docker.DockerClient = docker.from_env()
            containers = []

            for _ in range(test_config.get("runnerCount", 1)):
                container = create_docker_container(client, image, env, run_id)
                LOGGER.info("successfully created container %s",
                            container.name)
                containers.append(container)

            try:
                new_state = run_test_with_timeout(
                    test_config=rendered_test_config,
                    incoming_state=state,
                    hostnames=[
                        f"{container.name}:50051" for container in containers
                    ],
                    duration=rendered_test_config.get("timeout", 15),
                )
            except (AssertionError, ValueError, TypeError,
                    RuntimeError) as err:
                # NOTE: May need to fine tune exception types
                LOGGER.error("Error running test %s: %s",
                             test_config["name"],
                             err,
                             exc_info=True)

                for container in containers:
                    LOGGER.debug("Stopping runner %s", container.name)
                    container.stop(timeout=3)

                new_state = {
                    test_config["name"]: {
                        "summary":
                        TestSummary(
                            description=test_config.get("description"),
                            error=str(err),
                            completed_cycles=0,
                            remaining_asserts=[],
                            duration=0,
                        )
                    }
                }

            for container in containers:
                LOGGER.debug("Stopping runner %s", container.name)
                container.stop(timeout=3)
        except (AssertionError, ValueError, TypeError, RuntimeError) as err:
            LOGGER.error("Error creating test %s: %s",
                         test_config["name"],
                         err,
                         exc_info=True)
            new_state = {
                test_config["name"]: {
                    "summary":
                    TestSummary(
                        description=test_config.get("description"),
                        error=str(err),
                        completed_cycles=0,
                        remaining_asserts=[],
                        duration=0,
                    )
                }
            }

        return {**state, **new_state}