Pytest с Moto, изменение статуса запроса athena с помощью серверной части

#python #amazon-web-services #unit-testing #boto3 #moto

#python #amazon-веб-сервисы #модульное тестирование #boto3 #moto

Вопрос:

Я использую moto для тестирования функциональности aws в моей кодовой базе. Одна из проблем, с которыми я столкнулся, заключается в том, что при тестировании athena статус запроса оставался в «QUEUED» на неопределенный срок, что приводило к сбою теста или тайм-ауту.

Вот метод, который нужно протестировать:

 import time
import boto3

class Athena:

    CLIENT = boto3.client("athena")

    class QueryError(Exception):
        """A class for exceptions related to queries."""

    @classmethod
    def execute_query(cls, query, result_location, check_status=True, 
    time_limit=10):
        """
        Execute a query in Athena.
        """

        _result_configuration = {"OutputLocation": result_location}

        _kwargs = {"QueryString": query, "ResultConfiguration": 
        _result_configuration}

        response = cls.CLIENT.start_query_execution(**_kwargs)
        query_id = response["QueryExecutionId"]

        if check_status:
            old_time = time.time()
            while True:
                status = cls.CLIENT.get_query_execution(
                QueryExecutionId=query_id)
                status = status["QueryExecution"]["Status"]["State"]
                    if status in ["SUCCEEDED", "FAILED", "CANCELLED"]:
                        if status == "FAILED":
                            raise cls.QueryError("error")
                        break
                    time.sleep(0.2)  # 200ms

                    if time.time() - old_time > time_limit and status 
                    == "QUEUED":
                        raise cls.QueryError("time limit reached")

        return query_id
 

Вот приспособление, переданное в тест

 from moto.s3 import mock_s3
import boto3

@pytest.fixture
def s3():
    with mock_s3():
        s3 = boto3.client("s3")
        yield s3
 

Вот тест (имейте в виду, что вам нужно перейти from x на модуль с помощью вышеуказанного метода)

 import uuid
import boto3
import pytest
from moto.athena import mock_athena
from moto.s3 import mock_s3


@mock_s3
@mock_athena
def test_execute_query_check(s3):
    from x import Athena

    """
    Test for 'execute_query' (with status check)
    """
    CLIENT = s3
    bucket_name = "pytest."   str(uuid.uuid4())

    # Bucket creation
    bucket_config = {"LocationConstraint": "us-east-2"}
    CLIENT.create_bucket(Bucket=bucket_name, 
    CreateBucketConfiguration=bucket_config)
    waiter = CLIENT.get_waiter("bucket_exists")
    waiter.wait(Bucket=bucket_name)

    s3_location = f"s3://{bucket_name}/"
    query = "SELECT current_date, current_time;"
    query_id = Athena.execute_query(query, s3_location, 
    check_status=True)
    assert query_id
 

Этот тест завершается неудачей, потому moto что не изменяет статус запроса в прошлом "QUEUED" , и тест ожидает изменения состояния, в противном случае это вызывает исключение.

Я хотел бы иметь возможность делать что-то вроде:

 from moto.athena import athena_backends
athena_backends['us-east-2'].job_flows[query_id].state = "SUCCEEDED"
 

как было предложено в этом выпуске: https://github.com/spulec/moto/issues/380

Однако атрибут «потоки заданий», похоже, больше не существует в серверной части boto3 mapreduce, и я не могу найти способ явно изменить его. В идеале это могло бы произойти где-нибудь в тесте, чтобы вручную изменить состояние запроса, чтобы смоделировать, как это будет с реальными ресурсами.

Комментарии:

1. Я думаю, что людям помогло бы ответить на ваш вопрос, если бы вы исправили отступы в своих примерах кода, поскольку python чувствителен к пробелам.

2. Да, ты прав, я над этим

Ответ №1:

Доступ к состоянию и его изменение можно получить следующим образом:

 athena_backends['us-east-2'].executions.get(query_id).status
 

Пример фрагмента кода

 from moto.athena import athena_backends
query = "SELECT stuff"
location = "s3://bucket-name/prefix/"
database = "database"
# Start Query
exex_id = self.client.start_query_execution(
   QueryString=query,
   QueryExecutionContext={"Database": database},
   ResultConfiguration={"OutputLocation": location},
)["QueryExecutionId"]
athena_backends['us-west-2'].executions.get(exex_id).status = "CANCELLED"
 

Комментарии:

1. извините, я устал, и я назначил награду за неправильный ответ. Тем не менее, это правильно.

2. RIP Bounty. Рад, что смог помочь.

Ответ №2:

Мне кажется, что moto возвращает только QUEUED для start_query_execution , вы можете взглянуть на исходный код здесь.

Используется другой подход from unittest import mock , и тогда вы можете сделать что-то вроде:

 cls.CLIENT = mock.Mock()
cls.CLIENT.start_query_execution.side_effect = [
    'QUEUED',
    'SUCCEEDED'
]

 

Итак, при первом cls.CLIENT.start_query_execution(..) вызове он вернет сообщение о том, что запрос находится в очереди, но во второй раз вернет сообщение об успешном выполнении, и тогда вы сможете протестировать оба пути выполнения.

Кроме того, с moto его помощью вы не сможете протестировать все случаи, потому что, кроме статуса в очереди, вы можете установить статус запроса только на CANCELLED , как вы можете видеть здесь .