|
40 | 40 | DataRecord,
|
41 | 41 | )
|
42 | 42 | from aws_lambda_powertools.utilities.idempotency.serialization.custom_dict import CustomDictSerializer
|
| 43 | +from aws_lambda_powertools.utilities.idempotency.serialization.dataclass import DataclassSerializer |
43 | 44 | from aws_lambda_powertools.utilities.idempotency.serialization.pydantic import PydanticSerializer
|
44 | 45 | from aws_lambda_powertools.utilities.validation import envelopes, validator
|
45 | 46 | from tests.functional.idempotency.utils import (
|
@@ -1380,6 +1381,115 @@ def collect_payment(payment: PaymentInput) -> dict:
|
1380 | 1381 | return PaymentOutput(**payment.dict())
|
1381 | 1382 |
|
1382 | 1383 |
|
| 1384 | +@pytest.mark.parametrize("output_serializer_type", ["explicit", "deduced"]) |
| 1385 | +def test_idempotent_function_serialization_dataclass(output_serializer_type: str): |
| 1386 | + # GIVEN |
| 1387 | + dataclasses = get_dataclasses_lib() |
| 1388 | + config = IdempotencyConfig(use_local_cache=True) |
| 1389 | + mock_event = {"customer_id": "fake", "transaction_id": "fake-id"} |
| 1390 | + idempotency_key = f"{TESTS_MODULE_PREFIX}.test_idempotent_function_serialization_dataclass.<locals>.collect_payment#{hash_idempotency_key(mock_event)}" # noqa E501 |
| 1391 | + persistence_layer = MockPersistenceLayer(expected_idempotency_key=idempotency_key) |
| 1392 | + |
| 1393 | + @dataclasses.dataclass |
| 1394 | + class PaymentInput: |
| 1395 | + customer_id: str |
| 1396 | + transaction_id: str |
| 1397 | + |
| 1398 | + @dataclasses.dataclass |
| 1399 | + class PaymentOutput: |
| 1400 | + customer_id: str |
| 1401 | + transaction_id: str |
| 1402 | + |
| 1403 | + if output_serializer_type == "explicit": |
| 1404 | + output_serializer = DataclassSerializer( |
| 1405 | + model=PaymentOutput, |
| 1406 | + ) |
| 1407 | + else: |
| 1408 | + output_serializer = DataclassSerializer |
| 1409 | + |
| 1410 | + @idempotent_function( |
| 1411 | + data_keyword_argument="payment", |
| 1412 | + persistence_store=persistence_layer, |
| 1413 | + config=config, |
| 1414 | + output_serializer=output_serializer, |
| 1415 | + ) |
| 1416 | + def collect_payment(payment: PaymentInput) -> PaymentOutput: |
| 1417 | + return PaymentOutput(**dataclasses.asdict(payment)) |
| 1418 | + |
| 1419 | + # WHEN |
| 1420 | + payment = PaymentInput(**mock_event) |
| 1421 | + first_call: PaymentOutput = collect_payment(payment=payment) |
| 1422 | + assert first_call.customer_id == payment.customer_id |
| 1423 | + assert first_call.transaction_id == payment.transaction_id |
| 1424 | + assert isinstance(first_call, PaymentOutput) |
| 1425 | + second_call: PaymentOutput = collect_payment(payment=payment) |
| 1426 | + assert isinstance(second_call, PaymentOutput) |
| 1427 | + assert second_call.customer_id == payment.customer_id |
| 1428 | + assert second_call.transaction_id == payment.transaction_id |
| 1429 | + |
| 1430 | + |
| 1431 | +def test_idempotent_function_serialization_dataclass_failure_no_return_type(): |
| 1432 | + # GIVEN |
| 1433 | + dataclasses = get_dataclasses_lib() |
| 1434 | + config = IdempotencyConfig(use_local_cache=True) |
| 1435 | + mock_event = {"customer_id": "fake", "transaction_id": "fake-id"} |
| 1436 | + idempotency_key = f"{TESTS_MODULE_PREFIX}.test_idempotent_function_serialization_pydantic_failure_no_return_type.<locals>.collect_payment#{hash_idempotency_key(mock_event)}" # noqa E501 |
| 1437 | + persistence_layer = MockPersistenceLayer(expected_idempotency_key=idempotency_key) |
| 1438 | + |
| 1439 | + @dataclasses.dataclass |
| 1440 | + class PaymentInput: |
| 1441 | + customer_id: str |
| 1442 | + transaction_id: str |
| 1443 | + |
| 1444 | + @dataclasses.dataclass |
| 1445 | + class PaymentOutput: |
| 1446 | + customer_id: str |
| 1447 | + transaction_id: str |
| 1448 | + |
| 1449 | + idempotent_function_decorator = idempotent_function( |
| 1450 | + data_keyword_argument="payment", |
| 1451 | + persistence_store=persistence_layer, |
| 1452 | + config=config, |
| 1453 | + output_serializer=DataclassSerializer, |
| 1454 | + ) |
| 1455 | + with pytest.raises(IdempotencyNoSerializationModelError, match="No serialization model was supplied"): |
| 1456 | + |
| 1457 | + @idempotent_function_decorator |
| 1458 | + def collect_payment(payment: PaymentInput): |
| 1459 | + return PaymentOutput(**payment.dict()) |
| 1460 | + |
| 1461 | + |
| 1462 | +def test_idempotent_function_serialization_dataclass_failure_bad_type(): |
| 1463 | + # GIVEN |
| 1464 | + dataclasses = get_dataclasses_lib() |
| 1465 | + config = IdempotencyConfig(use_local_cache=True) |
| 1466 | + mock_event = {"customer_id": "fake", "transaction_id": "fake-id"} |
| 1467 | + idempotency_key = f"{TESTS_MODULE_PREFIX}.test_idempotent_function_serialization_pydantic_failure_no_return_type.<locals>.collect_payment#{hash_idempotency_key(mock_event)}" # noqa E501 |
| 1468 | + persistence_layer = MockPersistenceLayer(expected_idempotency_key=idempotency_key) |
| 1469 | + |
| 1470 | + @dataclasses.dataclass |
| 1471 | + class PaymentInput: |
| 1472 | + customer_id: str |
| 1473 | + transaction_id: str |
| 1474 | + |
| 1475 | + @dataclasses.dataclass |
| 1476 | + class PaymentOutput: |
| 1477 | + customer_id: str |
| 1478 | + transaction_id: str |
| 1479 | + |
| 1480 | + idempotent_function_decorator = idempotent_function( |
| 1481 | + data_keyword_argument="payment", |
| 1482 | + persistence_store=persistence_layer, |
| 1483 | + config=config, |
| 1484 | + output_serializer=PydanticSerializer, |
| 1485 | + ) |
| 1486 | + with pytest.raises(IdempotencyModelTypeError, match="Model type is not inherited from pydantic BaseModel"): |
| 1487 | + |
| 1488 | + @idempotent_function_decorator |
| 1489 | + def collect_payment(payment: PaymentInput) -> dict: |
| 1490 | + return PaymentOutput(**payment.dict()) |
| 1491 | + |
| 1492 | + |
1383 | 1493 | def test_idempotent_function_arbitrary_args_kwargs():
|
1384 | 1494 | # Scenario to validate we can use idempotent_function with a function
|
1385 | 1495 | # with an arbitrary number of args and kwargs
|
|
0 commit comments