Exemple #1
0
        public string ReadCloudSchedulerData(CloudEvent cloudEvent)
        {
            _logger.LogInformation("Reading cloud scheduler data");

            string country = null;

            switch (cloudEvent.Type)
            {
            case EVENT_TYPE_PUBSUB:
                var messagePublishedData = CloudEventConverters.ConvertCloudEventData <MessagePublishedData>(cloudEvent);
                var pubSubMessage        = messagePublishedData.Message;
                _logger.LogInformation($"Type: {EVENT_TYPE_PUBSUB} data: {pubSubMessage.Data.ToBase64()}");

                country = pubSubMessage.Data.ToStringUtf8();
                break;

            case EVENT_TYPE_SCHEDULER:
                // Data: {"custom_data":"Q3lwcnVz"}
                var schedulerJobData = CloudEventConverters.ConvertCloudEventData <SchedulerJobData>(cloudEvent);
                _logger.LogInformation($"Type: {EVENT_TYPE_SCHEDULER} data: {schedulerJobData.CustomData.ToBase64()}");

                country = schedulerJobData.CustomData.ToStringUtf8();
                break;
            }

            _logger.LogInformation($"Extracted country: {country}");
            return(country);
        }
        private static async Task <T> ConvertAndDeserialize <T>(string resourceName) where T : class
        {
            var context    = GcfEventResources.CreateHttpContext(resourceName);
            var cloudEvent = await GcfConverters.ConvertGcfEventToCloudEvent(context.Request);

            return(CloudEventConverters.ConvertCloudEventData <T>(cloudEvent));
        }
Exemple #3
0
        public void GetDataConverter_Cached()
        {
            var converter1 = CloudEventConverters.GetDataConverter <EventData>();
            var converter2 = CloudEventConverters.GetDataConverter <EventData>();

            Assert.Same(converter1, converter2);
        }
Exemple #4
0
        public void PopulateCloudEvent_Valid()
        {
            var evt  = new CloudEvent("type", new Uri("//source"));
            var data = new EventData {
                Text = "some text"
            };

            CloudEventConverters.PopulateCloudEvent(evt, data);
            Assert.Equal("some text", evt.Data);
        }
Exemple #5
0
        public void ConvertEventData_Valid()
        {
            var evt = new CloudEvent("type", new Uri("//source"))
            {
                Data = "some text"
            };
            var data = CloudEventConverters.ConvertCloudEventData <EventData>(evt);

            Assert.Equal("some text", data.Text);
        }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger <Startup> logger)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        logger.LogInformation("Service is starting...");

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapPost("/", async context =>
            {
                logger.LogInformation("Handling HTTP POST");

                var ceId = context.Request.Headers["ce-id"];
                if (string.IsNullOrEmpty(ceId))
                {
                    context.Response.StatusCode = StatusCodes.Status400BadRequest;
                    await context.Response.WriteAsync("Bad Request: expected header ce-id");
                    return;
                }

                var cloudEvent        = await context.Request.ReadCloudEventAsync();
                var storageObjectData = CloudEventConverters.ConvertCloudEventData <StorageObjectData>(cloudEvent);
                logger.LogInformation(
                    $"Detected change in GCS bucket: {storageObjectData.Bucket}, object name: {storageObjectData.Name}");

                // reply with a cloudevent
                var replyEvent = new CloudEvent(
                    CloudEventsSpecVersion.V1_0,
                    "com.example.kuberun.events.received",
                    new Uri("https://localhost"),
                    Guid.NewGuid().ToString(),
                    DateTime.Now)
                {
                    DataContentType = new ContentType(MediaTypeNames.Application.Json),
                    Data            = JsonConvert.SerializeObject("Event received")
                };

                // TODO: there should be a more concise way to construct the response.
                context.Response.StatusCode = StatusCodes.Status200OK;
                context.Response.Headers.Add("Ce-Id", replyEvent.Id);
                context.Response.Headers.Add("Ce-Specversion", "1.0");
                context.Response.Headers.Add("Ce-Type", replyEvent.Type);
                context.Response.Headers.Add("Ce-Source", replyEvent.Source.ToString());
                context.Response.ContentType = MediaTypeNames.Application.Json;
                await context.Response.WriteAsync(replyEvent.Data.ToString());
            });
        });
    }
        public (string, string) ReadCloudStorageData(CloudEvent cloudEvent)
        {
            _logger.LogInformation("Reading cloud storage data");

            string bucket = null, name = null;

            switch (cloudEvent.Type)
            {
            case EVENT_TYPE_AUDITLOG:
                //"protoPayload" : {"resourceName":"projects/_/buckets/events-atamel-images-input/objects/atamel.jpg}";

                var logEntryData = CloudEventConverters.ConvertCloudEventData <LogEntryData>(cloudEvent);
                var tokens       = logEntryData.ProtoPayload.ResourceName.Split('/');
                bucket = tokens[3];
                name   = tokens[5];
                break;

            case EVENT_TYPE_STORAGE:
                var storageObjectData = CloudEventConverters.ConvertCloudEventData <StorageObjectData>(cloudEvent);
                bucket = storageObjectData.Bucket;
                name   = storageObjectData.Name;
                break;

            case EVENT_TYPE_PUBSUB:
                // {"message": {
                //     "data": "eyJidWNrZXQiOiJldmVudHMtYXRhbWVsLWltYWdlcy1pbnB1dCIsIm5hbWUiOiJiZWFjaC5qcGcifQ==",
                // },"subscription": "projects/events-atamel/subscriptions/cre-europe-west1-trigger-resizer-sub-000"}

                var messagePublishedData = CloudEventConverters.ConvertCloudEventData <MessagePublishedData>(cloudEvent);
                var pubSubMessage        = messagePublishedData.Message;
                _logger.LogInformation($"Type: {EVENT_TYPE_PUBSUB} data: {pubSubMessage.Data.ToBase64()}");

                var decoded = pubSubMessage.Data.ToStringUtf8();
                _logger.LogInformation($"decoded: {decoded}");

                var parsed = JValue.Parse(decoded);
                bucket = (string)parsed["bucket"];
                name   = (string)parsed["name"];
                break;

            default:
                // Data: {"bucket":"knative-atamel-images-input","name":"beach.jpg"}
                _logger.LogInformation($"Type: {cloudEvent.Type} data: {cloudEvent.Data}");

                var parsedCustom = JValue.Parse((string)cloudEvent.Data);
                bucket = (string)parsedCustom["bucket"];
                name   = (string)parsedCustom["name"];
                break;
            }
            _logger.LogInformation($"Extracted bucket: {bucket}, name: {name}");
            return(bucket, name);
        }
Exemple #8
0
        public async Task NoRetry(PubsubMessage message)
        {
            var cloudEvent = new CloudEvent(MessagePublishedData.MessagePublishedCloudEventType, new Uri("//pubsub.googleapis.com"));
            var data       = new MessagePublishedData {
                Message = message
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            await ExecuteCloudEventRequestAsync(cloudEvent);

            var logEntry = Assert.Single(GetFunctionLogEntries());

            Assert.Equal(LogLevel.Information, logEntry.Level);
            Assert.Equal("Not retrying...", logEntry.Message);
        }
        public async Task CloudEventInput()
        {
            var cloudEvent = new CloudEvent(StorageObjectData.FinalizedCloudEventType, new Uri("//storage.googleapis.com"));
            var data       = new StorageObjectData {
                Name = "new-file.txt"
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            await ExecuteCloudEventRequestAsync(cloudEvent);

            var logEntry = Assert.Single(GetFunctionLogEntries());

            Assert.Equal("File new-file.txt uploaded", logEntry.Message);
            Assert.Equal(LogLevel.Information, logEntry.Level);
        }
        public async Task ObjectDeletedEvent()
        {
            var cloudEvent = new CloudEvent(StorageObjectData.DeletedCloudEventType, new Uri("//storage.googleapis.com"));
            var data       = new StorageObjectData {
                Name = "new-file.txt"
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            await ExecuteCloudEventRequestAsync(cloudEvent);

            var logEntry = Assert.Single(GetFunctionLogEntries());

            Assert.Equal($"Unsupported event type: {StorageObjectData.DeletedCloudEventType}", logEntry.Message);
            Assert.Equal(LogLevel.Warning, logEntry.Level);
        }
Exemple #11
0
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger <Startup> logger)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            logger.LogInformation("Service is starting...");

            app.UseRouting();

            var bucketImages = GetEnvironmentVariable("BUCKET_IMAGES");

            _bucketThumbnails = GetEnvironmentVariable("BUCKET_THUMBNAILS");
            _projectId        = GetEnvironmentVariable("PROJECT_ID");

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapPost("/", async context =>
                {
                    var cloudEvent = await context.Request.ReadCloudEventAsync();
                    logger.LogInformation("Received CloudEvent\n" + GetEventLog(cloudEvent));

                    if (EVENT_TYPE_AUDITLOG != cloudEvent.Type)
                    {
                        logger.LogInformation($"Event type '{cloudEvent.Type}' is not {EVENT_TYPE_AUDITLOG}, ignoring.");
                        return;
                    }

                    //"protoPayload" : {"resourceName":"projects/_/buckets/events-atamel-images-input/objects/atamel.jpg}";
                    var logEntryData = CloudEventConverters.ConvertCloudEventData <LogEntryData>(cloudEvent);
                    var tokens       = logEntryData.ProtoPayload.ResourceName.Split('/');
                    var bucket       = tokens[3];
                    var objectName   = tokens[5];

                    if (bucketImages != bucket)
                    {
                        logger.LogInformation($"Bucket '{bucket}' is not same as {bucketImages}, ignoring.");
                        return;
                    }

                    await DeleteFromThumbnailsAsync(objectName, logger);

                    await DeleteFromFirestore(objectName, logger);
                });
            });
        }
Exemple #12
0
        public (string, string) ReadCloudStorageData(CloudEvent cloudEvent)
        {
            _logger.LogInformation("Reading cloud storage data");

            string bucket = null, name = null;

            switch (cloudEvent.Type)
            {
            case EVENT_TYPE_AUDITLOG:
                var logEntryData = CloudEventConverters.ConvertCloudEventData <LogEntryData>(cloudEvent);
                var tokens       = logEntryData.ProtoPayload.ResourceName.Split('/');
                bucket = tokens[3];
                name   = tokens[5];
                break;

            case EVENT_TYPE_STORAGE:
                var storageObjectData = CloudEventConverters.ConvertCloudEventData <StorageObjectData>(cloudEvent);
                bucket = storageObjectData.Bucket;
                name   = storageObjectData.Name;
                break;

            case EVENT_TYPE_PUBSUB:

                var messagePublishedData = CloudEventConverters.ConvertCloudEventData <MessagePublishedData>(cloudEvent);
                var pubSubMessage        = messagePublishedData.Message;
                _logger.LogInformation($"Type: {EVENT_TYPE_PUBSUB} data: {pubSubMessage.Data.ToBase64()}");

                var decoded = pubSubMessage.Data.ToStringUtf8();
                _logger.LogInformation($"decoded: {decoded}");

                var parsed = JValue.Parse(decoded);
                bucket = (string)parsed["bucket"];
                name   = (string)parsed["name"];
                break;

            default:
                _logger.LogInformation($"Type: {cloudEvent.Type} data: {cloudEvent.Data}");

                var parsedCustom = JValue.Parse((string)cloudEvent.Data);
                bucket = (string)parsedCustom["bucket"];
                name   = (string)parsedCustom["name"];
                break;
            }
            _logger.LogInformation($"Extracted bucket: {bucket}, name: {name}");
            return(bucket, name);
        }
        public async Task ExecuteCloudEventAsync_CloudEvent()
        {
            var cloudEvent = new CloudEvent(
                StorageObjectData.FinalizedCloudEventType,
                new Uri("//storage", UriKind.RelativeOrAbsolute));
            var data = new StorageObjectData {
                Name = "test1"
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            using var test = new Test <StorageObjectFunction>();
            await test.ExecuteCloudEventRequestAsync(cloudEvent);

            var log = Assert.Single(test.GetFunctionLogEntries());

            Assert.Equal("Name: test1", log.Message);
        }
Exemple #14
0
        /// <summary>
        /// Convenience method to test CloudEvents by supplying only the most important aspects.
        /// This method simply constructs a CloudEvent from the parameters and delegates to
        /// <see cref="ExecuteCloudEventRequestAsync(CloudEvent)"/>.
        /// </summary>
        /// <param name="eventType">The CloudEvent type.</param>
        /// <param name="data">The data to populate the CloudEvent with. The data should be convertible
        /// via <see cref="CloudEventConverters"/>.</param>
        /// <param name="source">The source URI for the CloudEvent, or null to use a default of "//test-source".</param>
        /// <param name="subject">The subject of the CloudEvent, or null if no subject is required.</param>
        /// <typeparam name="T">The type of the event data. This is used to find the appropriate data converter.</typeparam>
        public Task ExecuteCloudEventRequestAsync <T>(string eventType, T?data, Uri?source = null, string?subject = null)
            where T : class
        {
            var cloudEvent = new CloudEvent(
                eventType,
                source ?? new Uri("//test-source", UriKind.RelativeOrAbsolute),
                id: Guid.NewGuid().ToString());

            if (data is object)
            {
                CloudEventConverters.PopulateCloudEvent(cloudEvent, data);
            }
            if (subject is object)
            {
                cloudEvent.Subject = subject;
            }
            return(ExecuteCloudEventRequestAsync(cloudEvent));
        }
Exemple #15
0
        public async Task RetryTrue()
        {
            var cloudEvent = new CloudEvent(MessagePublishedData.MessagePublishedCloudEventType, new Uri("//pubsub.googleapis.com"));
            var data       = new MessagePublishedData
            {
                Message = new PubsubMessage {
                    TextData = "{ \"retry\": true }"
                }
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            // The test server propagates the exception to the caller. The real server would respond
            // with a status code of 500.
            await Assert.ThrowsAsync <InvalidOperationException>(() => ExecuteCloudEventRequestAsync(cloudEvent));

            Assert.Empty(GetFunctionLogEntries());
        }
Exemple #16
0
        public async Task MessageWithoutTextData()
        {
            var cloudEvent = new CloudEvent(MessagePublishedData.MessagePublishedCloudEventType, new Uri("//pubsub.googleapis.com"));
            var data       = new MessagePublishedData
            {
                Message = new PubsubMessage {
                    Attributes = { { "key", "value" } }
                }
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            await ExecuteCloudEventRequestAsync(cloudEvent);

            var logEntry = Assert.Single(GetFunctionLogEntries());

            Assert.Equal("Hello world", logEntry.Message);
            Assert.Equal(LogLevel.Information, logEntry.Level);
        }
        public async Task Processing(string textData, int ageInSeconds, string expectedLog)
        {
            var cloudEvent = new CloudEvent(MessagePublishedData.MessagePublishedCloudEventType,
                                            new Uri("//pubsub.googleapis.com"), "1234", DateTime.UtcNow.AddSeconds(-ageInSeconds));
            var data = new MessagePublishedData {
                Message = new PubsubMessage {
                    TextData = textData
                }
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            await ExecuteCloudEventRequestAsync(cloudEvent);

            var logEntry = Assert.Single(GetFunctionLogEntries());

            Assert.Equal(LogLevel.Information, logEntry.Level);
            Assert.Equal(expectedLog, logEntry.Message);
        }
Exemple #18
0
        /// <summary>
        /// Handles an HTTP request by extracting the Cloud Event from it, deserializing the data, and passing
        /// both the event and the data to the original Cloud Event Function.
        /// The request fails if it does not contain a Cloud Event.
        /// </summary>
        /// <param name="context">The HTTP context containing the request and response.</param>
        /// <returns>A task representing the asynchronous operation.</returns>
        public async Task HandleAsync(HttpContext context)
        {
            CloudEvent cloudEvent;
            TData      data;

            try
            {
                cloudEvent = await CloudEventConverter.ConvertRequest(context.Request);

                data = CloudEventConverters.ConvertCloudEventData <TData>(cloudEvent);
            }
            catch (CloudEventConverter.ConversionException e)
            {
                _logger.LogError(e.Message);
                context.Response.StatusCode = 400;
                return;
            }

            await _function.HandleAsync(cloudEvent, data, context.RequestAborted);
        }
        public async Task FileNameIsLogged()
        {
            // Prepare the inputs
            var cloudEvent = new CloudEvent(StorageObjectData.FinalizedCloudEventType, new Uri("//storage.googleapis.com"));
            var data       = new StorageObjectData {
                Name = "new-file.txt"
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);
            var logger = new MemoryLogger <HelloGcs.Function>();

            // Execute the function
            var function = new HelloGcs.Function(logger);
            await function.HandleAsync(cloudEvent, data, CancellationToken.None);

            // Check the log results
            var logEntry = Assert.Single(logger.ListLogEntries());

            Assert.Equal("File new-file.txt uploaded", logEntry.Message);
            Assert.Equal(LogLevel.Information, logEntry.Level);
        }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger <Startup> logger)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        logger.LogInformation("Service is starting...");

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapPost("/", async context =>
            {
                var cloudEvent = await context.Request.ReadCloudEventAsync();
                logger.LogInformation("Received CloudEvent\n" + GetEventLog(cloudEvent));

                var messagePublishedData = CloudEventConverters.ConvertCloudEventData <MessagePublishedData>(cloudEvent);
                var pubSubMessage        = messagePublishedData.Message;
                if (pubSubMessage == null)
                {
                    context.Response.StatusCode = 400;
                    await context.Response.WriteAsync("Bad request: Invalid Pub/Sub message format");
                    return;
                }

                var data = pubSubMessage.Data;
                logger.LogInformation($"Data: {data.ToBase64()}");

                var name = data.ToStringUtf8();
                logger.LogInformation($"Extracted name: {name}");

                var id = context.Request.Headers["ce-id"];
                await context.Response.WriteAsync($"Hello {name}! ID: {id}");
            });
        });
    }
        public async Task CloudEventIsLogged()
        {
            var client = Server.CreateClient();

            var created    = DateTimeOffset.UtcNow.AddMinutes(-5);
            var updated    = created.AddMinutes(2);
            var cloudEvent = new CloudEvent(StorageObjectData.DeletedCloudEventType, new Uri("//storage.googleapis.com"), "1234");
            var data       = new StorageObjectData
            {
                Name           = "new-file.txt",
                Bucket         = "my-bucket",
                Metageneration = 23,
                TimeCreated    = new DateTimeOffset(2020, 7, 9, 13, 0, 5, TimeSpan.Zero).ToTimestamp(),
                Updated        = new DateTimeOffset(2020, 7, 9, 13, 23, 25, TimeSpan.Zero).ToTimestamp()
            };

            CloudEventConverters.PopulateCloudEvent(cloudEvent, data);

            await ExecuteCloudEventRequestAsync(cloudEvent);

            var logs = GetFunctionLogEntries();

            Assert.All(logs, entry => Assert.Equal(LogLevel.Information, entry.Level));

            var actualMessages   = logs.Select(entry => entry.Message).ToArray();
            var expectedMessages = new[]
            {
                "Event: 1234",
                $"Event Type: {StorageObjectData.DeletedCloudEventType}",
                "Bucket: my-bucket",
                "File: new-file.txt",
                "Metageneration: 23",
                "Created: 2020-07-09T13:00:05",
                "Updated: 2020-07-09T13:23:25",
            };

            Assert.Equal(expectedMessages, actualMessages);
        }
Exemple #22
0
 public void GetDataConverter_DoesntImplementInterface() =>
 Assert.Throws <InvalidOperationException>(() => CloudEventConverters.GetDataConverter <NoImplementationData>());
Exemple #23
0
 public void GetDataConverter_WrongTargetType() =>
 Assert.Throws <InvalidOperationException>(() => CloudEventConverters.GetDataConverter <WrongTargetTypeData>());
Exemple #24
0
 public void GetDataConverter_NoAttribute() =>
 Assert.Throws <InvalidOperationException>(() => CloudEventConverters.GetDataConverter <NoAttributeData>());