Example #1
0
def test_given_bad_condition(mocker, condition_verifications, expected_status):
    mocker.patch(f"{PKG}.now", return_value=sentinel.starts)

    def _analyze_context(context: Context) -> Analyzer:
        assert context == Context(foo="bar",
                                  starts=sentinel.starts,
                                  base_url=sentinel.base_url)
        return sentinel.context_analyzer

    analyze_context = mocker.patch(f"{PKG}.MappingAnalyzer",
                                   side_effect=_analyze_context)

    def _verify(
        verification: Verification,
        analyzer: Analyzer,
        context: Optional[Context] = None,
    ) -> Verification:
        assert analyzer is sentinel.context_analyzer
        assert context == Context(foo="bar",
                                  starts=sentinel.starts,
                                  base_url=sentinel.base_url)
        return verification

    conditions = [
        NonCallableMock(Description,
                        verify=Mock(side_effect=partial(_verify, v)))
        for v in condition_verifications
    ]
    case = Case(
        label=sentinel.label,
        conditions=conditions,
        request=sentinel.request,
        response=sentinel.response,
    )

    unit_runner = NonCallableMock(UnitRunner, base_url=sentinel.base_url)
    listener = NonCallableMock(CaseListener)
    runner = CaseRunner(unit_runner=unit_runner, listener=listener)
    result = runner.run(case, context=Context(foo="bar"))

    assert result.label is sentinel.label
    assert result.status is expected_status

    # Contextual values will disappear.
    for condition in conditions:
        condition.verify.assert_called_once_with(sentinel.context_analyzer,
                                                 Context(foo="bar"))
    analyze_context.assert_called_once_with(Context(foo="bar"))

    unit_runner.run.assert_not_called()
    listener.on_execution.assert_not_called()
Example #2
0
def test_when_given_an_response(mocker):
    mocker.patch(f"{PKG}.now", return_value=sentinel.starts)

    execution = ExecutionReport(status=Status.SUCCESS, starts=sentinel.starts)
    verification = ResponseVerification(
        response_id=sentinel.response_id,
        status_code=Verification.succeed(),
        headers=Verification.succeed(),
        body=Verification(status=Status.UNSTABLE),
    )

    case = Case(label=sentinel.label,
                request=sentinel.request,
                response=sentinel.response)

    def _run_unit(
        request: Request,
        requirements: ResponseDescription,
        session: Optional[requests.Session] = None,
        context: Optional[Context] = None,
    ) -> Result:
        assert request is sentinel.request
        assert requirements is sentinel.response
        assert session is sentinel.session
        assert context == Context(foo="bar",
                                  starts=sentinel.starts,
                                  base_url=sentinel.base_url)
        return execution, sentinel.response, verification

    unit_runner = NonCallableMock(UnitRunner, base_url=sentinel.base_url)
    unit_runner.run.side_effect = Mock(side_effect=_run_unit)
    listener = NonCallableMock(spec=CaseListener)
    runner = CaseRunner(unit_runner=unit_runner, listener=listener)
    result = runner.run(case,
                        session=sentinel.session,
                        context=Context(foo="bar"))

    assert result.label is sentinel.label
    assert result.status is Status.UNSTABLE
    assert result.execution is execution
    assert result.response is verification

    # Contextual values will disappear.
    unit_runner.run.assert_called_once_with(
        request=sentinel.request,
        requirements=sentinel.response,
        session=sentinel.session,
        context=Context(foo="bar"),
    )
    listener.on_execution.assert_called_once_with(execution, sentinel.response)
Example #3
0
def test_ordered(mocker):
    mocker.patch(f"{PKG}.now", side_effect=[sentinel.starts1, sentinel.starts2])

    cases_task_ctor = mocker.patch(f"{PKG}.OrderedCasesTask", return_value=sentinel.cases_task)
    task_ctor = mocker.patch(f"{PKG}.RunningScenarioTask", return_value=sentinel.task)

    sentinel.context.starts = sentinel.starts

    subscenario = Scenario(label=sentinel.subscenario_label)
    scenario = Scenario(label=sentinel.label, cases=sentinel.cases, subscenarios=[subscenario])

    case_runner = NonCallableMock(CaseRunner, base_url=sentinel.base_url)
    runner = ScenarioRunner(executor=sentinel.executor, case_runner=case_runner)
    task = runner.submit(scenario)
    assert task is sentinel.task

    cases_task_ctor.assert_has_calls(
        [
            call(
                sentinel.executor,
                case_runner,
                sentinel.cases,
                context=Context(starts=sentinel.starts1, base_url=sentinel.base_url),
            ),
            call(
                sentinel.executor,
                case_runner,
                [],
                context=Context(starts=sentinel.starts2, base_url=sentinel.base_url),
            ),
        ]
    )
    task_ctor.assert_has_calls(
        [
            call(
                label=sentinel.subscenario_label,
                conditions=Verification.collect([]),
                cases=sentinel.cases_task,
                subscenarios=[],
            ),
            call(
                label=sentinel.label,
                conditions=Verification(status=Status.SKIPPED, children=[]),
                cases=sentinel.cases_task,
                subscenarios=[sentinel.task],
            ),
        ]
    )
Example #4
0
def test_given_no_response(mocker):
    retry = mocker.patch(f"{PKG}.retry_while_false", side_effect=_retry)

    requester = NonCallableMock(Requester)
    requester.base_url = sentinel.requester_base_url
    requester.execute.return_value = (sentinel.execution, None)

    requirements = NonCallableMock(ResponseDescription)

    runner = UnitRunner(requester)
    assert runner.base_url is sentinel.requester_base_url

    execution, response, verification = runner.run(sentinel.request,
                                                   requirements)
    assert execution is sentinel.execution
    assert response is None
    assert verification is None

    requester.execute.assert_called_once_with(sentinel.request,
                                              session=None,
                                              context=Context())
    requirements.verify.assert_not_called()
    retry.assert_called_once_with(ANY,
                                  attempts=1,
                                  delay=0.1,
                                  predicate=predicate)
Example #5
0
def test_closed_context():
    context = Context(
        control=sentinel.control,
        normal=sentinel.normal_out_of_context,
        deleted=sentinel.deleted_out_of_context,
        overwritten=sentinel.overwritten_out_of_context,
    )

    with closed_context(
            context,
            normal=sentinel.normal_in_context,
            deleted=sentinel.deleted_in_context,
            overwritten=sentinel.overwritten_in_context,
            contextual=sentinel.contextual,
    ) as context:
        assert context["control"] is sentinel.control
        assert context["normal"] is sentinel.normal_in_context
        assert context["deleted"] is sentinel.deleted_in_context
        assert context["overwritten"] is sentinel.overwritten_in_context
        assert context["contextual"] is sentinel.contextual

        del context["deleted"]
        context["overwritten"] = sentinel.overwritten_new
        context["not_contextual"] = sentinel.not_contextual

    assert context["control"] is sentinel.control
    assert context["normal"] is sentinel.normal_out_of_context
    assert context["deleted"] is sentinel.deleted_out_of_context
    assert context["overwritten"] is sentinel.overwritten_out_of_context
    assert context["not_contextual"] is sentinel.not_contextual
    assert "contextual" not in context
Example #6
0
def test_given_not_satisfied_conditions(mocker, statuses, expected_status):
    mocker.patch(f"{PKG}.now", return_value=sentinel.starts)

    analyze_context = mocker.patch(f"{PKG}.MappingAnalyzer")
    analyze_context.return_value = sentinel.context_analyzer

    ordered_cases_task_ctor = mocker.patch(f"{PKG}.OrderedCasesTask")
    unordered_cases_task_ctor = mocker.patch(f"{PKG}.UnorderedCasesTask")
    task_ctor = mocker.patch(f"{PKG}.StaticScenarioTask", return_value=sentinel.task)

    verifications = [Verification(status) for status in statuses]
    conditions = [NonCallableMock(Description, verify=Mock(return_value=v)) for v in verifications]

    scenario = Scenario(
        label=sentinel.label,
        conditions=conditions,
        cases=sentinel.cases,
        subscenarios=[sentinel.subscenario],
    )
    case_runner = NonCallableMock(CaseRunner, base_url=sentinel.base_url)
    runner = ScenarioRunner(executor=sentinel.executor, case_runner=case_runner)
    task = runner.submit(scenario)
    assert task is sentinel.task

    result = task_ctor.call_args[0][0]
    assert result.label is sentinel.label
    assert result.status is expected_status
    assert result.conditions.children == verifications
    assert result.cases.status is Status.SKIPPED
    assert not result.cases.items
    assert result.subscenarios.status is Status.SKIPPED
    assert not result.subscenarios.items

    for condition in conditions:
        condition.verify.assert_called_once_with(
            sentinel.context_analyzer,
            Context(starts=sentinel.starts, base_url=sentinel.base_url),
        )

    analyze_context.assert_called_once_with(
        Context(starts=sentinel.starts, base_url=sentinel.base_url)
    )
    ordered_cases_task_ctor.assert_not_called()
    unordered_cases_task_ctor.assert_not_called()
Example #7
0
 def _verify(
     verification: Verification,
     analyzer: Analyzer,
     context: Optional[Context] = None,
 ) -> Verification:
     assert analyzer is sentinel.context_analyzer
     assert context == Context(foo="bar",
                               starts=sentinel.starts,
                               base_url=sentinel.base_url)
     return verification
Example #8
0
def test_given_a_response(mocker):
    retry = mocker.patch(f"{PKG}.retry_while_false", side_effect=_retry)

    execution = ExecutionReport(starts=sentinel.starts)
    requester = NonCallableMock(Requester)
    requester.base_url = sentinel.requester_base_url
    requester.execute.return_value = (execution, sentinel.response)

    def _verify(analyzer: Analyzer,
                context: Optional[Context] = None) -> Verification:
        assert analyzer is sentinel.response
        assert context == Context(foo="bar", starts=sentinel.starts)
        return sentinel.verification

    requirements = NonCallableMock(ResponseDescription,
                                   verify=Mock(side_effect=_verify))

    runner = UnitRunner(requester=requester, retry=3, delay=sentinel.delay)
    assert runner.base_url is sentinel.requester_base_url

    execution, response, verification = runner.run(
        sentinel.request,
        requirements,
        sentinel.session,
        context=Context(foo="bar"),
    )
    assert execution is execution
    assert response is sentinel.response
    assert verification is sentinel.verification

    requester.execute.assert_called_with(
        sentinel.request,
        session=sentinel.session,
        context=Context(foo="bar"),
    )
    # Contextual values will disappear.
    requirements.verify.assert_called_with(sentinel.response,
                                           Context(foo="bar"))
    retry.assert_called_once_with(ANY,
                                  attempts=4,
                                  delay=sentinel.delay,
                                  predicate=ANY)
Example #9
0
 def _run_unit(
     request: Request,
     requirements: ResponseDescription,
     session: Optional[requests.Session] = None,
     context: Optional[Context] = None,
 ) -> Result:
     assert request is sentinel.request
     assert requirements is sentinel.response
     assert session is None
     assert context == Context(starts=sentinel.starts,
                               base_url=sentinel.base_url)
     return execution, None, None
Example #10
0
    def execute(
        self,
        request: Request,
        session: Optional[requests.Session] = None,
        context: Optional[Context] = None,
    ) -> Tuple[ExecutionReport, Optional[Response]]:
        """
        Executes a request.

        Args:
            request: A request.
            session: A session object to execute.
            context: Execution context.
        Returns:
            A tuple of execution report and response.
            When there is no response, the response will be ``None``.
        """
        if session is None:
            with requests.Session() as new_session:
                return self.execute(request, session=new_session)

        context = context if context is not None else Context()
        starts = now()
        report = ExecutionReport(starts=starts)
        try:
            with closed_context(context, starts=starts) as context:
                prepped = self._prepare_request(request, context)
            proxies = session.rebuild_proxies(prepped, proxies=None)
        except Exception as error:
            message = to_message(error)
            report = replace(report, status=Status.FAILURE, message=message)
            return report, None

        report = replace(
            report,
            request=PreparedRequest(
                method=prepped.method or "",
                url=prepped.url or "",
                headers=prepped.headers,
                body=prepped.body,
            ),
        )

        try:
            res = session.send(prepped, proxies=proxies, timeout=self._timeout)
        except Exception as error:
            message = to_message(error)
            report = replace(report, status=Status.UNSTABLE, message=message)
            return report, None

        report = replace(report, status=Status.SUCCESS)
        response = ResponseWrapper(id=_generate_id(), res=res)
        return report, response
Example #11
0
 def run(
     self,
     request: Request,
     requirements: ResponseDescription,
     session: Optional[requests.Session] = None,
     context: Optional[Context] = None,
 ) -> Result:
     context = context if context is not None else Context()
     return retry_while_false(
         partial(self._execute, request, requirements, session, context),
         attempts=self._retry + 1,
         delay=self._delay,
         predicate=predicate,
     )
Example #12
0
    def submit(self, scenario: Scenario) -> ScenarioTask:
        starts = now()
        context = Context(
            **{
                CONTEXT_KEY_STARTS: starts,
                CONTEXT_KEY_BASE_URL: self._case_runner.base_url,
            })

        context_analyzer = MappingAnalyzer(context)
        conditions = Verification.collect(
            condition.verify(context_analyzer, context)
            for condition in scenario.conditions)
        if not conditions.status.is_succeeded:
            status = Status.SKIPPED
            if conditions.status is Status.FAILURE:
                status = Status.FAILURE

            result = ScenarioResult(label=scenario.label,
                                    status=status,
                                    conditions=conditions)
            return StaticScenarioTask(result)

        if scenario.ordered:
            cases: CasesTask = OrderedCasesTask(
                self._executor,
                self._case_runner,
                scenario.cases,
                context=context,
            )
        else:
            cases = UnorderedCasesTask(self._executor, self._case_runner,
                                       scenario.cases)
        subscenarios = [
            self.submit(subscenario) for subscenario in scenario.subscenarios
        ]
        return RunningScenarioTask(
            label=scenario.label,
            conditions=conditions,
            cases=cases,
            subscenarios=subscenarios,
        )
Example #13
0
def test_when_given_no_response(mocker):
    mocker.patch(f"{PKG}.now", return_value=sentinel.starts)

    execution = ExecutionReport(status=Status.FAILURE)
    case = Case(label=sentinel.label,
                request=sentinel.request,
                response=sentinel.response)

    def _run_unit(
        request: Request,
        requirements: ResponseDescription,
        session: Optional[requests.Session] = None,
        context: Optional[Context] = None,
    ) -> Result:
        assert request is sentinel.request
        assert requirements is sentinel.response
        assert session is None
        assert context == Context(starts=sentinel.starts,
                                  base_url=sentinel.base_url)
        return execution, None, None

    unit_runner = NonCallableMock(UnitRunner, base_url=sentinel.base_url)
    unit_runner.run.side_effect = Mock(side_effect=_run_unit)
    listener = NonCallableMock(spec=CaseListener)
    runner = CaseRunner(unit_runner=unit_runner, listener=listener)
    result = runner.run(case)

    assert result.label is sentinel.label
    assert result.status is Status.FAILURE
    assert result.execution is execution
    assert result.response is None

    # Contextual values will disappear.
    unit_runner.run.assert_called_once_with(
        request=sentinel.request,
        requirements=sentinel.response,
        session=None,
        context=Context(),
    )
    listener.on_execution.assert_called_once_with(execution, None)
Example #14
0
class CaseRunner:
    def __init__(self,
                 unit_runner: UnitRunner,
                 listener: Optional[CaseListener] = None):
        self._unit_runner = unit_runner
        self._listener = listener or CaseListener()

    @property
    def base_url(self) -> str:
        return self._unit_runner.base_url

    def run(
        self,
        case: Case,
        session: Optional[requests.Session] = None,
        context: Optional[Context] = None,
    ) -> CaseResult:
        if not case.enabled:
            return CaseResult(label=case.label)

        context = context if context is not None else Context()
        with closed_context(context, starts=now(),
                            base_url=self.base_url) as context:
            context_analyzer = MappingAnalyzer(context)
            conditions = Verification.collect(
                condition.verify(context_analyzer, context)
                for condition in case.conditions)
            if not conditions.status.is_succeeded:
                return CaseResult(case.label, conditions)

            execution, response, verification = self._unit_runner.run(
                request=case.request,
                requirements=case.response,
                session=session,
                context=context,
            )
        self._listener.on_execution(execution, response)

        return CaseResult(case.label, conditions, execution, verification)
Example #15
0
 def resolve(self, context: Optional[Context] = None) -> object:
     context = context or Context()
     return context.get(self._key)
Example #16
0
def test_context():
    context = Context(foo="bar")
    assert list(context) == ["foo"]
    assert context != {"foo": "bar"}
    assert context == Context(foo="bar")
Example #17
0
 def _analyze_context(context: Context) -> Analyzer:
     assert context == Context(foo="bar",
                               starts=sentinel.starts,
                               base_url=sentinel.base_url)
     return sentinel.context_analyzer
Example #18
0
 def _verify(analyzer: Analyzer,
             context: Optional[Context] = None) -> Verification:
     assert analyzer is sentinel.response
     assert context == Context(foo="bar", starts=sentinel.starts)
     return sentinel.verification