示例#1
0
def test_log_metric_invalid_unit(invalid_input, expected):
    # GIVEN invalid units are provided
    # WHEN log_metric is called
    # THEN ValueError exception should be raised

    with pytest.raises(expected):
        log_metric(name="test_metric", **invalid_input)
示例#2
0
def test_log_metric(capsys):
    # GIVEN a service, unit and value have been provided
    # WHEN log_metric is called
    # THEN custom metric line should be match given values
    log_metric(service="payment", name="test_metric", unit=MetricUnit.Seconds, value=60)
    expected = "MONITORING|60|Seconds|test_metric|ServerlessAirline|service=payment\n"
    captured = capsys.readouterr()

    assert captured.out == expected
示例#3
0
def test_log_metric_partially_correct_args(capsys, invalid_input, expected):
    # GIVEN invalid arguments are provided such as empty dimension values and metric units in strings
    # WHEN log_metric is called
    # THEN default values should be used such as "Count" as a unit, invalid dimensions not included
    # and no exception raised
    log_metric(name="test_metric", **invalid_input)
    captured = capsys.readouterr()

    assert captured.out == expected
示例#4
0
def test_log_metric_multiple_dimensions(capsys):
    # GIVEN multiple optional dimensions are provided
    # WHEN log_metric is called
    # THEN dimensions should appear as dimenion=value
    log_metric(
        name="test_metric", unit=MetricUnit.Seconds, value=60, customer="abc", charge_id="123"
    )
    expected = "MONITORING|60|Seconds|test_metric|ServerlessAirline|service=service_undefined,customer=abc,charge_id=123\n"
    captured = capsys.readouterr()

    assert captured.out == expected
示例#5
0
def test_log_metric_env_var(monkeypatch, capsys):
    # GIVEN a service, unit and value have been provided
    # WHEN log_metric is called
    # THEN custom metric line should be match given values
    service_name = "payment"
    monkeypatch.setenv("POWERTOOLS_SERVICE_NAME", service_name)

    log_metric(name="test_metric", unit=MetricUnit.Seconds, value=60)
    expected = "MONITORING|60|Seconds|test_metric|ServerlessAirline|service=payment\n"
    captured = capsys.readouterr()

    assert captured.out == expected
示例#6
0
def lambda_handler(event, context):
    """AWS Lambda Function entrypoint to cancel booking

    Parameters
    ----------
    event: dict, required
        Step Functions State Machine event

        chargeId: string
            pre-authorization charge ID

    context: object, required
        Lambda Context runtime methods and attributes
        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    boolean

    Raises
    ------
    BookingCancellationException
        Booking Cancellation Exception including error message upon failure
    """
    global _cold_start
    if _cold_start:
        log_metric(name="ColdStart",
                   unit=MetricUnit.Count,
                   value=1,
                   function_name=context.function_name)
        _cold_start = False

    booking_id = event.get("bookingId")

    if not booking_id:
        log_metric(name="InvalidBookingRequest",
                   unit=MetricUnit.Count,
                   value=1,
                   operation="cancel_booking")
        logger.error({"operation": "invalid_event", "details": event})
        raise ValueError("Invalid booking ID")

    try:
        logger.debug(f"Cancelling booking - {booking_id}")
        ret = cancel_booking(booking_id)

        log_metric(name="SuccessfulCancellation",
                   unit=MetricUnit.Count,
                   value=1)
        logger.debug("Adding Booking Status annotation")
        tracer.put_annotation("BookingStatus", "CANCELLED")

        return ret
    except BookingCancellationException as err:
        log_metric(name="FailedCancellation", unit=MetricUnit.Count, value=1)
        logger.debug("Adding Booking Status annotation before raising error")
        tracer.put_annotation("BookingStatus", "ERROR")
        logger.error({"operation": "cancel_booking", "details": err})

        raise BookingCancellationException(details=err)
def lambda_handler(event, context):
    """AWS Lambda Function entrypoint to reserve a booking

    Parameters
    ----------
    event: dict, required
        Step Functions State Machine event

        chargeId: string
            pre-authorization charge ID

        stateExecutionId: string
            Step Functions Process Booking Execution ID

        chargeId: string
            Pre-authorization payment token

        customerId: string
            Customer unique identifier

        bookingOutboundFlightId: string
            Outbound flight unique identifier

    context: object, required
        Lambda Context runtime methods and attributes
        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    bookingId: string
        booking ID generated

    Raises
    ------
    BookingReservationException
        Booking Reservation Exception including error message upon failure
    """
    global _cold_start
    if _cold_start:
        log_metric(name="ColdStart",
                   unit=MetricUnit.Count,
                   value=1,
                   function_name=context.function_name)
        _cold_start = False

    if not is_booking_request_valid(event):
        log_metric(
            name="InvalidBookingRequest",
            unit=MetricUnit.Count,
            value=1,
            operation="reserve_booking",
        )
        logger.error({"operation": "invalid_event", "details": event})
        raise ValueError("Invalid booking request")

    try:
        logger.debug(f"Reserving booking for customer {event['customerId']}")
        ret = reserve_booking(event)

        log_metric(name="SuccessfulReservation",
                   unit=MetricUnit.Count,
                   value=1)
        logger.debug("Adding Booking Reservation annotation")
        tracer.put_annotation("Booking", ret["bookingId"])
        tracer.put_annotation("BookingStatus", "RESERVED")

        # Step Functions use the return to append `bookingId` key into the overall output
        return ret["bookingId"]
    except BookingReservationException as err:
        log_metric(name="FailedReservation", unit=MetricUnit.Count, value=1)
        logger.debug(
            "Adding Booking Reservation annotation before raising error")
        tracer.put_annotation("BookingStatus", "ERROR")
        logger.error({"operation": "reserve_booking", "details": err})
        raise BookingReservationException(details=err)
def lambda_handler(event, context):
    """AWS Lambda Function entrypoint to confirm booking

    Parameters
    ----------
    event: dict, required
        Step Functions State Machine event

        bookingId: string
            Unique Booking ID of an unconfirmed booking

    context: object, required
        Lambda Context runtime methods and attributes
        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    string
        bookingReference generated

    Raises
    ------
    BookingConfirmationException
        Booking Confirmation Exception including error message upon failure
    """

    global _cold_start
    if _cold_start:
        log_metric(name="ColdStart",
                   unit=MetricUnit.Count,
                   value=1,
                   function_name=context.function_name)
        _cold_start = False

    booking_id = event.get("bookingId")
    if not booking_id:
        log_metric(
            name="InvalidBookingRequest",
            unit=MetricUnit.Count,
            value=1,
            operation="confirm_booking",
        )
        logger.error({"operation": "invalid_event", "details": event})
        raise ValueError("Invalid booking ID")

    try:
        logger.debug(f"Confirming booking - {booking_id}")
        ret = confirm_booking(booking_id)

        log_metric(name="SuccessfulBooking", unit=MetricUnit.Count, value=1)
        logger.debug("Adding Booking Status annotation")
        tracer.put_annotation("BookingReference", ret["bookingReference"])
        tracer.put_annotation("BookingStatus", "CONFIRMED")

        # Step Functions use the return to append `bookingReference` key into the overall output
        return ret["bookingReference"]
    except BookingConfirmationException as err:
        log_metric(name="FailedBooking", unit=MetricUnit.Count, value=1)
        logger.debug("Adding Booking Status annotation before raising error")
        tracer.put_annotation("BookingStatus", "ERROR")
        logger.error({"operation": "confirm_booking", "details": err})

        raise BookingConfirmationException(details=err)
def lambda_handler(event, context):
    """AWS Lambda Function entrypoint to refund payment

    Parameters
    ----------
    event: dict, required
        Step Functions State Machine event

        chargeId: string
            pre-authorization charge ID

    context: object, required
        Lambda Context runtime methods and attributes
        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    string
        JSON Stringified data containing refundId ID

    Raises
    ------
    RefundException
        Refund Exception including error message upon failure
    """

    global _cold_start
    if _cold_start:
        log_metric(name="ColdStart",
                   unit=MetricUnit.Count,
                   value=1,
                   function_name=context.function_name)
        _cold_start = False

    payment_token = event.get("chargeId")
    customer_id = event.get("customerId")

    if not payment_token:
        log_metric(name="InvalidPaymentRequest",
                   unit=MetricUnit.Count,
                   value=1,
                   operation="refund_payment")
        logger.error({"operation": "invalid_event", "details": event})
        raise ValueError("Invalid Charge ID")

    try:
        logger.debug(
            f"Refunding payment from customer {customer_id} using {payment_token} token"
        )
        ret = refund_payment(payment_token)

        log_metric(name="SuccessfulRefund", unit=MetricUnit.Count, value=1)
        logger.debug("Adding Payment Refund Status annotation")
        tracer.put_annotation("Refund", ret["refundId"])
        tracer.put_annotation("PaymentStatus", "REFUNDED")

        return ret
    except RefundException as err:
        log_metric(name="FailedRefund", unit=MetricUnit.Count, value=1)
        logger.debug(
            "Adding Payment Refund Status annotation before raising error")
        tracer.put_annotation("RefundStatus", "FAILED")
        logger.error({"operation": "refund_payment", "details": err})
        raise RefundException(details=err)
示例#10
0
def lambda_handler(event, context):
    """AWS Lambda Function entrypoint to collect payment

    Parameters
    ----------
    event: dict, required
        Step Functions State Machine event

        chargeId: string
            pre-authorization charge ID

    context: object, required
        Lambda Context runtime methods and attributes
        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    dict
        receiptUrl: string
            receipt URL of charge collected

        price: int
            amount collected

    Raises
    ------
    BookingConfirmationException
        Booking Confirmation Exception including error message upon failure
    """
    global _cold_start
    if _cold_start:
        log_metric(
            name="ColdStart", unit=MetricUnit.Count, value=1, function_name=context.function_name
        )
        _cold_start = False

    pre_authorization_token = event.get("chargeId")
    customer_id = event.get("customerId")

    if not pre_authorization_token:
        log_metric(
            name="InvalidPaymentRequest",
            unit=MetricUnit.Count,
            value=1,
            operation="collect_payment",
        )
        logger.error({"operation": "invalid_event", "details": event})
        raise ValueError("Invalid Charge ID")

    try:
        logger.debug(
            f"Collecting payment from customer {customer_id} using {pre_authorization_token} token"
        )
        ret = collect_payment(pre_authorization_token)

        log_metric(name="SuccessfulPayment", unit=MetricUnit.Count, value=1)
        logger.debug("Adding Payment Status annotation")
        tracer.put_annotation("PaymentStatus", "SUCCESS")

        # Step Functions can append multiple values if you return a single dict
        return ret
    except PaymentException as err:
        log_metric(name="FailedPayment", unit=MetricUnit.Count, value=1)
        logger.debug("Adding Payment Status annotation before raising error")
        tracer.put_annotation("PaymentStatus", "FAILED")
        logger.error({"operation": "collect_payment", "details": err})
        raise PaymentException(details=err)
示例#11
0
def lambda_handler(event, context):
    """AWS Lambda Function entrypoint to notify booking

    Parameters
    ----------
    event: dict, required
        Step Functions State Machine event

        customer_id: string
            Unique Customer ID

        price: string
            Flight price

        bookingReference: string
            Confirmed booking reference

    context: object, required
        Lambda Context runtime methods and attributes
        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    string
        notificationId
            Unique ID confirming notification delivery

    Raises
    ------
    BookingNotificationException
        Booking Notification Exception including error message upon failure
    """

    global _cold_start
    if _cold_start:
        log_metric(name="ColdStart",
                   unit=MetricUnit.Count,
                   value=1,
                   function_name=context.function_name)
        _cold_start = False

    customer_id = event.get("customerId", False)
    payment = event.get("payment", {})
    price = payment.get("price", False)
    booking_reference = event.get("bookingReference", False)

    if not customer_id and not price:
        log_metric(name="InvalidBookingRequest",
                   unit=MetricUnit.Count,
                   value=1,
                   operation="notify_booking")
        logger.error({"operation": "invalid_event", "details": event})
        raise ValueError("Invalid customer and price")

    try:
        payload = {"customerId": customer_id, "price": price}
        ret = notify_booking(payload, booking_reference)

        log_metric(name="SuccessfulNotification",
                   unit=MetricUnit.Count,
                   value=1)
        logger.debug("Adding Booking Notification annotation")
        tracer.put_annotation("BookingNotification", ret["notificationId"])
        tracer.put_annotation("BookingNotificationStatus", "SUCCESS")

        # Step Functions use the return to append `notificationId` key into the overall output
        return ret["notificationId"]
    except BookingNotificationException as err:
        log_metric(name="FailedNotification", unit=MetricUnit.Count, value=1)
        logger.debug(
            "Adding Booking Notification annotation before raising error")
        tracer.put_annotation("BookingNotificationStatus", "FAILED")
        logger.error({"operation": "notify_booking", "details": err})
        raise BookingNotificationException(details=err)