async def test_delete_500_purge_instance_history(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[500, MESSAGE_500])
    client = DurableOrchestrationClient(binding_string)
    client._delete_async_request = mock_request.delete

    with pytest.raises(Exception):
        await client.purge_instance_history(TEST_INSTANCE_ID)
async def test_get_500_get_status_all_failed(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/",
                               response=[500, MESSAGE_500])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    with pytest.raises(Exception):
        await client.get_status_all()
def test_get_start_new_url(binding_string):
    client = DurableOrchestrationClient(binding_string)
    instance_id = "2e2568e7-a906-43bd-8364-c81733c5891e"
    function_name = "my_function"
    start_new_url = client._get_start_new_url(instance_id, function_name)
    expected_url = replace_stand_in_bits(
        f"{RPC_BASE_URL}orchestrators/{function_name}/{instance_id}")
    assert expected_url == start_new_url
async def test_delete_500_purge_instance_history_by(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/?runtimeStatus=Running",
                               response=[500, MESSAGE_500])
    client = DurableOrchestrationClient(binding_string)
    client._delete_async_request = mock_request.delete

    with pytest.raises(Exception):
        await client.purge_instance_history_by(
            runtime_status=[OrchestrationRuntimeStatus.Running])
async def test_delete_404_purge_instance_history(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[404, MESSAGE_404])
    client = DurableOrchestrationClient(binding_string)
    client._delete_async_request = mock_request.delete

    result = await client.purge_instance_history(TEST_INSTANCE_ID)
    assert result is not None
    assert result.instances_deleted == 0
async def test_get_404_get_status_failed(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[404, MESSAGE_404])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    result = await client.get_status(TEST_INSTANCE_ID)
    assert result is not None
    assert result.message == MESSAGE_404
async def test_delete_404_purge_instance_history_by(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/?runtimeStatus=Running",
                               response=[404, MESSAGE_404])
    client = DurableOrchestrationClient(binding_string)
    client._delete_async_request = mock_request.delete

    result = await client.purge_instance_history_by(
        runtime_status=[OrchestrationRuntimeStatus.Running])
    assert result is not None
    assert result.instances_deleted == 0
async def test_rewind_works_under_200_and_200_http_codes(binding_string):
    """Tests that the rewind API works as expected under 'successful' http codes: 200, 202"""
    client = DurableOrchestrationClient(binding_string)
    for code in [200, 202]:
        mock_request = MockRequest(
            expected_url=f"{RPC_BASE_URL}instances/{INSTANCE_ID}/rewind?reason={REASON}",
            response=[code, ""])
        client._post_async_request = mock_request.post
        result = await client.rewind(INSTANCE_ID, REASON)
        assert result is None
async def test_get_200_get_status_success(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[200, dict(createdTime=TEST_CREATED_TIME,
                                                   lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                                                   runtimeStatus="Completed")])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    result = await client.get_status(TEST_INSTANCE_ID)
    assert result is not None
    assert result.runtime_status == "Completed"
async def test_post_410_terminate(binding_string):
    raw_reason = 'stuff and things'
    reason = 'stuff%20and%20things'
    mock_request = MockRequest(
        expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}/terminate?reason={reason}",
        response=[410, None])
    client = DurableOrchestrationClient(binding_string)
    client._post_async_request = mock_request.post

    result = await client.terminate(TEST_INSTANCE_ID, raw_reason)
    assert result is None
async def test_post_500_terminate(binding_string):
    raw_reason = 'stuff and things'
    reason = 'stuff%20and%20things'
    mock_request = MockRequest(
        expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}/terminate?reason={reason}",
        response=[500, MESSAGE_500])
    client = DurableOrchestrationClient(binding_string)
    client._post_async_request = mock_request.post

    with pytest.raises(Exception):
        await client.terminate(TEST_INSTANCE_ID, raw_reason)
async def test_wait_or_response_check_status_response(binding_string):
    status = dict(createdTime=TEST_CREATED_TIME,
                  lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                  runtimeStatus="Running")
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[200, status])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    with pytest.raises(Exception):
        await client.wait_for_completion_or_create_check_status_response(
            None, TEST_INSTANCE_ID, timeout_in_milliseconds=500)
def test_create_check_status_response(binding_string):
    client = DurableOrchestrationClient(binding_string)
    instance_id = "2e2568e7-a906-43bd-8364-c81733c5891e"
    request = Mock(
        url=
        "http://test_azure.net/api/orchestrators/DurableOrchestrationTrigger")
    returned_response = client.create_check_status_response(
        request, instance_id)

    http_management_payload = {
        "id":
        instance_id,
        "statusQueryGetUri":
        r"http://test_azure.net/runtime/webhooks/durabletask/instances/"
        r"2e2568e7-a906-43bd-8364-c81733c5891e?taskHub"
        r"=TASK_HUB_NAME&connection=Storage&code=AUTH_CODE",
        "sendEventPostUri":
        r"http://test_azure.net/runtime/webhooks/durabletask/instances/"
        r"2e2568e7-a906-43bd-8364-c81733c5891e/raiseEvent/{"
        r"eventName}?taskHub=TASK_HUB_NAME&connection=Storage&code=AUTH_CODE",
        "terminatePostUri":
        r"http://test_azure.net/runtime/webhooks/durabletask/instances/"
        r"2e2568e7-a906-43bd-8364-c81733c5891e/terminate"
        r"?reason={text}&taskHub=TASK_HUB_NAME&connection=Storage&code=AUTH_CODE",
        "rewindPostUri":
        r"http://test_azure.net/runtime/webhooks/durabletask/instances/"
        r"2e2568e7-a906-43bd-8364-c81733c5891e/rewind?reason"
        r"={text}&taskHub=TASK_HUB_NAME&connection=Storage&code=AUTH_CODE",
        "purgeHistoryDeleteUri":
        r"http://test_azure.net/runtime/webhooks/durabletask/instances/"
        r"2e2568e7-a906-43bd-8364-c81733c5891e"
        r"?taskHub=TASK_HUB_NAME&connection=Storage&code=AUTH_CODE"
    }
    for key, _ in http_management_payload.items():
        http_management_payload[key] = replace_stand_in_bits(
            http_management_payload[key])
    expected_response = {
        "status_code": 202,
        "body": json.dumps(http_management_payload),
        "headers": {
            "Content-Type": "application/json",
            "Location": http_management_payload["statusQueryGetUri"],
            "Retry-After": "10",
        },
    }

    for k, v in expected_response.get("headers").items():
        assert v == returned_response.headers.get(k)
    assert expected_response.get(
        "status_code") == returned_response.status_code
    assert expected_response.get(
        "body") == returned_response.get_body().decode()
async def test_rewind_with_no_rpc_endpoint(binding_string):
    """Tests the behaviour of rewind without an RPC endpoint / under the legacy HTTP endpoint."""
    client = DurableOrchestrationClient(binding_string)
    mock_request = MockRequest(
        expected_url=f"{RPC_BASE_URL}instances/{INSTANCE_ID}/rewind?reason={REASON}",
        response=[-1, ""])
    client._post_async_request = mock_request.post  
    client._orchestration_bindings._rpc_base_url = None
    expected_exception_str = "The Python SDK only supports RPC endpoints."\
        + "Please remove the `localRpcEnabled` setting from host.json"
    with pytest.raises(Exception) as ex:
        await client.rewind(INSTANCE_ID, REASON)
    ex_message = str(ex.value)
    assert ex_message == expected_exception_str
def test_get_raise_event_url(binding_string):
    client = DurableOrchestrationClient(binding_string)
    instance_id = "2e2568e7-a906-43bd-8364-c81733c5891e"
    event_name = "test_event_name"
    task_hub_name = "test_task_hub"
    connection_name = "test_connection"
    raise_event_url = client._get_raise_event_url(instance_id, event_name, task_hub_name,
                                                  connection_name)

    expected_url = replace_stand_in_bits(
        f"{RPC_BASE_URL}instances/{instance_id}/raiseEvent/{event_name}"
        f"?taskHub=test_task_hub&connection=test_connection")

    assert expected_url == raise_event_url
async def test_wait_or_response_check_status_response(binding_string):
    status = dict(createdTime=TEST_CREATED_TIME,
                  lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                  runtimeStatus="Running")
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[200, status])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    request = Mock(url="http://test_azure.net/api/orchestrators/DurableOrchestrationTrigger")
    result = await client.wait_for_completion_or_create_check_status_response(
        request, TEST_INSTANCE_ID, timeout_in_milliseconds=2000)
    assert result is not None
    assert mock_request.get_count == 3
async def test_get_200_get_status_all_success(binding_string):
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/",
                               response=[200, [dict(createdTime=TEST_CREATED_TIME,
                                                    lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                                                    runtimeStatus="Running"),
                                               dict(createdTime=TEST_CREATED_TIME,
                                                    lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                                                    runtimeStatus="Running")
                                               ]])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    result = await client.get_status_all()
    assert result is not None
    assert len(result) == 2
async def test_start_new_orchestrator_not_found(binding_string):
    """Test that we throw the right exception when the orchestrator is not found.
    """
    status = dict(ExceptionMessage=EXCEPTION_ORCHESTRATOR_NOT_FOUND_EXMESSAGE,
                  StackTrace=STACK_TRACE,
                  Message=EXCEPTION_ORCHESTRATOR_NOT_FOUND_MESSAGE,
                  ExceptionType=EXCEPTION_TYPE_ORCHESTRATOR_NOT_FOUND)
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}orchestrators/{TEST_ORCHESTRATOR}",
                               response=[400, status])
    client = DurableOrchestrationClient(binding_string)
    client._post_async_request = mock_request.post

    with pytest.raises(Exception) as ex:
        await client.start_new(TEST_ORCHESTRATOR)
    ex.match(EXCEPTION_ORCHESTRATOR_NOT_FOUND_EXMESSAGE)
async def test_wait_or_response_200_failed(binding_string):
    status = dict(createdTime=TEST_CREATED_TIME,
                  lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                  runtimeStatus="Failed")
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[200, status])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    result = await client.wait_for_completion_or_create_check_status_response(
        None, TEST_INSTANCE_ID)
    assert result is not None
    assert result.status_code == 500
    assert result.mimetype == 'application/json'
    assert json.loads(result.get_body().decode()) == DurableOrchestrationStatus.from_json(
        status).to_json()
async def test_wait_or_response_200_completed(binding_string):
    output = 'Some output'
    mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/{TEST_INSTANCE_ID}",
                               response=[200, dict(createdTime=TEST_CREATED_TIME,
                                                   lastUpdatedTime=TEST_LAST_UPDATED_TIME,
                                                   runtimeStatus="Completed",
                                                   output=output)])
    client = DurableOrchestrationClient(binding_string)
    client._get_async_request = mock_request.get

    result = await client.wait_for_completion_or_create_check_status_response(
        None, TEST_INSTANCE_ID)
    assert result is not None
    assert result.status_code == 200
    assert result.mimetype == 'application/json'
    assert result.get_body().decode() == output
async def test_rewind_throws_exception_during_404_410_and_500_errors(binding_string):
    """Tests the behaviour of rewind under 'exception' http codes: 404, 410, 500"""
    client = DurableOrchestrationClient(binding_string)
    codes = [404, 410, 500]
    exception_strs = [
        f"No instance with ID {INSTANCE_ID} found.",
        "The rewind operation is only supported on failed orchestration instances.",
        "Something went wrong"
    ]
    for http_code, expected_exception_str in zip(codes, exception_strs):
        mock_request = MockRequest(
            expected_url=f"{RPC_BASE_URL}instances/{INSTANCE_ID}/rewind?reason={REASON}",
            response=[http_code, "Something went wrong"])
        client._post_async_request = mock_request.post

        with pytest.raises(Exception) as ex:
            await client.rewind(INSTANCE_ID, REASON)
        ex_message = str(ex.value)
        assert ex_message == expected_exception_str
def test_get_input_returns_json_string(binding_string):
    input_ = json.loads(binding_string)
    result = DurableOrchestrationClient._get_json_input(input_)
    input_as_string = json.dumps(input_)
    assert input_as_string == result
def test_get_input_returns_none_when_none_supplied():
    result = DurableOrchestrationClient._get_json_input(None)
    assert result is None