예제 #1
0
    def test_publish_one_message(self):
        self.graph.sns_producer.produce(created("foo"), data="data")

        assert_that(
            self.graph.sns_producer,
            published(has_media_type(created("foo")), ),
        )
예제 #2
0
 def make_media_type(self, event_info, discard_event_type=False):
     if discard_event_type:
         return created("{}".format(name_for(
             self.event_store.model_class), ))
     return created("{}.{}".format(
         name_for(self.event_store.model_class),
         event_info.event.event_type.name,
     ))
    def test_publish_one_message(self):
        self.graph.sns_producer.produce(created("foo"), data="data")

        assert_that(
            self.graph.sns_producer,
            published(
                has_media_type(created("foo")),
            ),
        )
예제 #4
0
    def test_publish_one_message(self):
        self.graph.sns_producer.produce(created("foo"), uri="http://localhost")

        assert_that(
            self.graph.sns_producer,
            published(
                all_of(
                    has_media_type(created("foo")),
                    has_uri("http://localhost"),
                ), ),
        )
    def test_publish_one_message(self):
        self.graph.sns_producer.produce(created("foo"), uri="http://localhost")

        assert_that(
            self.graph.sns_producer,
            published(
                all_of(
                    has_media_type(created("foo")),
                    has_uri("http://localhost"),
                ),
            ),
        )
예제 #6
0
class CustomMessageSchema(URIMessageSchema):
    """
    Message indicating that a resource was created

    """
    MEDIA_TYPE = created("Resource")
    enumField = EnumField(TestEnum, attribute="enum_field", required=True)
예제 #7
0
def test_publish_by_convention():
    """
    Message publishing can use this convention.

    """
    def loader(metadata):
        return dict(sns_topic_arns=dict(default="default", ))

    graph = create_object_graph("example", testing=True, loader=loader)

    graph.sns_producer.produce(created("foo"),
                               uri="http://example.com",
                               opaque_data=dict())

    assert_that(graph.sns_producer.sns_client.publish.call_count,
                is_(equal_to(1)))
    assert_that(graph.sns_producer.sns_client.publish.call_args[1]["TopicArn"],
                is_(equal_to("default")))
    assert_that(
        loads(graph.sns_producer.sns_client.publish.call_args[1]["Message"]),
        is_(
            equal_to({
                "mediaType": "application/vnd.globality.pubsub._.created.foo",
                "uri": "http://example.com",
                "opaqueData": {},
            })))
def test_codec_sqs_envelope():
    graph = create_object_graph("example", testing=True)
    consumer = None
    message_id = "message_id"
    receipt_handle = "receipt_handle"
    envelope = CodecSQSEnvelope(graph)

    media_type = created("foo")
    uri = "http://foo/id"

    sqs_message = envelope.parse_raw_message(consumer, dict(
        MessageId=message_id,
        ReceiptHandle=receipt_handle,
        Body=dumps(dict(
            Message=dumps(dict(
                mediaType=media_type,
                foo="bar",
                uri=uri,
            )),
        )),
    ))

    assert_that(sqs_message.content, is_(equal_to(dict(
        # NB: no foo key here because it's not part of the schema
        media_type=media_type,
        uri=uri,
    ))))
    assert_that(sqs_message.media_type, is_(equal_to(media_type)))
    assert_that(sqs_message.message_id, is_(equal_to(message_id)))
    assert_that(sqs_message.receipt_handle, is_(equal_to(receipt_handle)))
예제 #9
0
def write(args):
    loader = load_from_dict(
        sns_producer=dict(
            profile_name=args.profile,
            region_name=args.region,
        ),
        sns_topic_arns=dict(default=args.topic_arn, ),
    )

    graph = create_object_graph("pubsub", debug=args.debug, loader=loader)
    graph.use("pubsub_message_schema_registry")
    graph.use("sns_topic_arns")
    graph.use("sns_producer")
    graph.lock()

    if args.media_type.startswith("application"):
        media_type = args.media_type
    else:
        media_type = created(args.media_type)

    message_id = graph.sns_producer.produce(
        media_type=media_type,
        uri=args.uri,
    )
    print("Wrote SNS message: {}".format(message_id))  # noqa
예제 #10
0
    def test_publish_two_messages_non_strict(self):
        self.graph.sns_producer.produce(created("foo"), uri="http://localhost")
        self.graph.sns_producer.produce(created("bar"), uri="http://localhost")

        assert_that(
            self.graph.sns_producer,
            published_inanyorder(
                all_of(
                    has_media_type(created("bar")),
                    has_uri("http://localhost"),
                ),
                all_of(
                    has_media_type(created("foo")),
                    has_uri(),
                ),
            ),
        )
예제 #11
0
class MessageBatchSchema(PubSubMessageSchema):
    """
    A message indicating that a batch of messages needs to be published.

    """
    MEDIA_TYPE = created("batch_message")

    messages = fields.List(fields.Nested(BatchedMessageSchema), required=True)
    def test_publish_two_messages_non_strict(self):
        self.graph.sns_producer.produce(created("foo"), uri="http://localhost")
        self.graph.sns_producer.produce(created("bar"), uri="http://localhost")

        assert_that(
            self.graph.sns_producer,
            published_inanyorder(
                all_of(
                    has_media_type(created("bar")),
                    has_uri("http://localhost"),
                ),
                all_of(
                    has_media_type(created("foo")),
                    has_uri(),
                ),
            ),
        )
예제 #13
0
class MessageBatchSchema(PubSubMessageSchema):
    """
    A message indicating that a batch of messages needs to be published.

    """
    MEDIA_TYPE = created("batch_message")

    messages = fields.List(fields.Nested(BatchedMessageSchema), required=True)

    def deserialize_media_type(self, obj):
        return MessageBatchSchema.MEDIA_TYPE
예제 #14
0
def test_produce_custom_topic_environ():
    """
    Can set a custom topic via environment

    """
    key = "EXAMPLE__SNS_TOPIC_ARNS__CREATED__FOO__BAR_BAZ"
    environ[key] = "topic"
    graph = create_object_graph("example", testing=True, loader=load_from_environ)
    graph.sns_producer.produce(created("foo.bar_baz"), bar="baz")
    assert_that(graph.sns_producer.sns_client.publish.call_count, is_(equal_to(1)))
    assert_that(graph.sns_producer.sns_client.publish.call_args[1]["TopicArn"], is_(equal_to("topic")))
    def test_created(self):
        assert_that(
            created("Foo.Bar"),
            is_(equal_to("application/vnd.globality.pubsub._.created.foo.bar")),
        )

        assert_that(
            self.graph.pubsub_message_schema_registry.find(
                "application/vnd.globality.pubsub._.created.foo.bar",
            ).schema,
            is_(instance_of(URIMessageSchema)),
        )
예제 #16
0
    def test_created(self):
        assert_that(
            created("Foo.Bar"),
            is_(equal_to(
                "application/vnd.globality.pubsub._.created.foo.bar")),
        )

        assert_that(
            self.graph.pubsub_message_schema_registry.find(
                "application/vnd.globality.pubsub._.created.foo.bar", ).schema,
            is_(instance_of(URIMessageSchema)),
        )
    def test_handle_message_ignored(self):
        """
        Unsupported media types are ignored.

        """
        self.message.media_type = created("bar")
        assert_that(
            self.dispatcher.handle_message(
                message=self.message,
                bound_handlers=self.daemon.bound_handlers,
            ),
            has_properties(
                elapsed_time=greater_than(0.0),
                result=MessageHandlingResultType.IGNORED,
            ),
        )
예제 #18
0
    def test_handle_message_ignored(self):
        """
        Unsupported media types are ignored.

        """
        self.message.media_type = created("bar")
        assert_that(
            self.dispatcher.handle_message(
                message=self.message,
                bound_handlers=self.daemon.bound_handlers,
            ),
            has_properties(
                elapsed_time=greater_than(0.0),
                result=MessageHandlingResultType.IGNORED,
            ),
        )
예제 #19
0
def test_dispatch_by_convention():
    """
    Message dispatch can use this convention.

    """
    graph = create_object_graph("example", testing=True)

    media_type = created(Foo)

    assert_that(
        graph.pubsub_message_schema_registry[media_type].schema,
        is_(instance_of(URIMessageSchema)),
    )

    assert_that(
        graph.sqs_message_handler_registry[media_type],
        is_(equal_to(noop_handler)),
    )
예제 #20
0
def test_dispatch_by_uri_convention():
    """
    Message dispatch can use this convention.

    """
    daemon = ExampleDaemon.create_for_testing()
    graph = daemon.graph

    media_type = created(Foo)

    assert_that(
        graph.pubsub_message_schema_registry.find(media_type).schema,
        is_(instance_of(URIMessageSchema)),
    )

    assert_that(
        graph.sqs_message_handler_registry.find(media_type, daemon.bound_handlers),
        is_(equal_to(noop_handler)),
    )
예제 #21
0
def test_publish_by_uri_convention():
    """
    Message publishing can use this convention.

    """
    def loader(metadata):
        return dict(sns_topic_arns=dict(default="default", ))

    graph = create_object_graph("example", testing=True, loader=loader)

    published_time = str(time())
    with patch("microcosm_pubsub.producer.time") as mocked_time:
        mocked_time.return_value = published_time
        graph.sns_producer.produce(created("foo"),
                                   uri="http://example.com",
                                   opaque_data=dict())

    assert_that(graph.sns_producer.sns_client.publish.call_count,
                is_(equal_to(1)))
    assert_that(graph.sns_producer.sns_client.publish.call_args[1]["TopicArn"],
                is_(equal_to("default")))
    assert_that(
        loads(graph.sns_producer.sns_client.publish.call_args[1]["Message"]),
        is_(
            equal_to({
                "mediaType": "application/vnd.globality.pubsub._.created.foo",
                "uri": "http://example.com",
                "opaqueData": {
                    "X-Request-Published": published_time,
                },
            })))
    assert_that(
        graph.sns_producer.sns_client.publish.call_args[1]
        ["MessageAttributes"],
        is_(
            equal_to({
                "media_type": {
                    "DataType": "String",
                    "StringValue":
                    "application/vnd.globality.pubsub._.created.foo"
                },
            })))
예제 #22
0
def test_handle_with_skipping():
    """
    Test that skipping works

    """
    daemon = ExampleDaemon.create_for_testing()
    graph = daemon.graph

    content = dict(bar="baz")
    result = graph.sqs_message_dispatcher.handle_message(
        message=SQSMessage(
            consumer=None,
            content=content,
            media_type=created("bar"),
            message_id=MESSAGE_ID,
            receipt_handle=None,
        ),
        bound_handlers=daemon.bound_handlers,
    )
    assert_that(result, is_(equal_to(False)))
def test_publish_by_uri_convention():
    """
    Message publishing can use this convention.

    """
    def loader(metadata):
        return dict(
            sns_topic_arns=dict(
                default="default",
            )
        )

    graph = create_object_graph("example", testing=True, loader=loader)

    graph.sns_producer.produce(created("foo"), uri="http://example.com", opaque_data=dict())

    assert_that(graph.sns_producer.sns_client.publish.call_count, is_(equal_to(1)))
    assert_that(graph.sns_producer.sns_client.publish.call_args[1]["TopicArn"], is_(equal_to("default")))
    assert_that(loads(graph.sns_producer.sns_client.publish.call_args[1]["Message"]), is_(equal_to({
        "mediaType": "application/vnd.globality.pubsub._.created.foo",
        "uri": "http://example.com",
        "opaqueData": {},
    })))
예제 #24
0
def test_codec_sqs_envelope():
    graph = create_object_graph("example", testing=True)
    consumer = None
    message_id = "message_id"
    receipt_handle = "receipt_handle"
    envelope = CodecSQSEnvelope(graph)

    media_type = created("foo")
    uri = "http://foo/id"

    sqs_message = envelope.parse_raw_message(
        consumer,
        dict(
            MessageId=message_id,
            ReceiptHandle=receipt_handle,
            Body=dumps(
                dict(Message=dumps(
                    dict(
                        mediaType=media_type,
                        foo="bar",
                        uri=uri,
                    )), )),
        ))

    assert_that(
        sqs_message.content,
        is_(
            equal_to(
                dict(
                    # NB: no foo key here because it's not part of the schema
                    media_type=media_type,
                    uri=uri,
                ))))
    assert_that(sqs_message.media_type, is_(equal_to(media_type)))
    assert_that(sqs_message.message_id, is_(equal_to(message_id)))
    assert_that(sqs_message.receipt_handle, is_(equal_to(receipt_handle)))
예제 #25
0
        return DerivedSchema.MEDIA_TYPE


@schema
class DuckTypeSchema(Schema):
    """
    A duck typed schema

    """
    MEDIA_TYPE = "application/vnd.microcosm.duck"

    quack = fields.String()


@handles(DuckTypeSchema)
@handles(created("foo"))
@handles(deleted("foo"))
@handles(DerivedSchema.MEDIA_TYPE)
def noop_handler(message):
    return True


@handles(created("IgnoredResource"))
def skipping_handler(message):
    raise SkipMessage("Failed")


class ExampleDaemon(ConsumerDaemon):

    @property
    def name(self):
예제 #26
0
"""
from json import dumps, loads

from hamcrest import (assert_that, equal_to, instance_of, is_)
from microcosm.api import create_object_graph

from microcosm_pubsub.codecs import PubSubMessageCodec
from microcosm_pubsub.conventions import created, make_media_type, URIMessageSchema
from microcosm_pubsub.decorators import handles


class Foo(object):
    pass


@handles(created("foo"))
def noop_handler(message):
    return True


def test_make_media_type():
    """
    Media type construction should generate the correct type strings.

    """
    cases = [
        (("foo", ), dict(), "application/vnd.globality.pubsub._.created.foo"),
        (("foo", ), dict(public=True),
         "application/vnd.globality.pubsub.created.foo"),
        (("foo", ), dict(organization="example"),
         "application/vnd.example.pubsub._.created.foo"),
예제 #27
0
from microcosm.api import binding
from microcosm_pubsub.chain import assign

from microcosm_fastapi.pubsub.handlers.chain_handlers import ChainURIHandlerAsync
from microcosm_fastapi.pubsub.chain.chain import ChainAsync
from microcosm_logging.decorators import logger


class PizzaModel:
    def __init__(self, toppings):
        self.toppings = toppings


@logger
@binding("pizza_daemon_handler")
@handles(created("Pizza"))
class PizzaDaemonHandler(ChainURIHandlerAsync):
    def get_chain(self):
        return ChainAsync(
            assign("pizza.toppings").to("toppings"),
            self.process_topping_sync,
            self.process_topping_async,
        )

    def process_topping_sync(self, toppings):
        return toppings + "_processed"

    async def process_topping_async(self, toppings):
        if toppings == "pineapple":
            raise ValueError()
        return toppings + "_processed"
예제 #28
0
        return DerivedSchema.MEDIA_TYPE


@schema
class DuckTypeSchema(Schema):
    """
    A duck typed schema

    """
    MEDIA_TYPE = "application/vnd.microcosm.duck"

    quack = fields.String()


@handles(DuckTypeSchema)
@handles(created("foo"))
@handles(deleted("foo"))
@handles(DerivedSchema.MEDIA_TYPE)
def noop_handler(message):
    return True


@handles(created("IgnoredResource"))
def skipping_handler(message):
    raise SkipMessage("Failed")


class ExampleDaemon(ConsumerDaemon):
    @property
    def name(self):
        return "example"
예제 #29
0
        Passes message context.

        """
        headers = self.sqs_message_context(message)
        response = get(uri, headers=headers)
        if response.status_code == codes.not_found and self.nack_if_not_found:
            raise Nack(self.nack_timeout)
        response.raise_for_status()
        return response.json()

    def handle(self, message, uri, resource):
        return True


@binding("publish_message_batch")
@handles(created("BatchMessage"))
@logger
class PublishBatchMessage:
    def __init__(self, graph):
        self.sns_producer = graph.sns_producer

    def __call__(self, message):
        messages = message["messages"]
        for message in messages:
            self.sns_producer.publish_message(
                message["media_type"],
                message["message"],
                message["topic_arn"],
                message["opaque_data"],
            )
예제 #30
0
from urllib.parse import urljoin

import requests
from microcosm.decorators import binding
from microcosm_logging.decorators import logger
from microcosm_pubsub.chain import Chain, assign, extracts
from microcosm_pubsub.conventions import created
from microcosm_pubsub.decorators import handles
from microcosm_pubsub.errors import Nack, SkipMessage
from microcosm_pubsub.handlers import ChainURIHandler

from rob_onboarding.models.order_event_type import OrderEventType


@binding("order_fulfilled_handler")
@handles(created("DeliveryEvent.PizzaDelivered"))
@logger
class OrderFulfilledHandler(ChainURIHandler):
    def __init__(self, graph):
        super().__init__(graph)
        self.server_uri = "http://localhost:5000"

    @property
    def resource_name(self):
        return "delivery_event"

    def get_chain(self):
        return Chain(
            assign("delivery_event.orderId").to("order_id"),
            self.extract_order,
            assign("order.customerId").to("customer_id"),