public void Should_not_create_job_if_too_old() { var e = new ContentCreated { SchemaId = new NamedId <Guid>(Guid.NewGuid(), "my-schema"), AppId = new NamedId <Guid>(Guid.NewGuid(), "my-event") }; var now = SystemClock.Instance.GetCurrentInstant(); var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); var ruleEnvelope = Envelope.Create(e); ruleEnvelope.SetTimestamp(now.Minus(Duration.FromDays(3))); var actionData = new RuleJobData(); var actionDescription = "MyDescription"; var eventName = "MySchemaCreatedEvent"; A.CallTo(() => clock.GetCurrentInstant()) .Returns(now); A.CallTo(() => ruleTriggerHandler.Triggers(A <Envelope <AppEvent> > .Ignored, ruleConfig.Trigger)) .Returns(true); A.CallTo(() => ruleActionHandler.CreateJob(A <Envelope <AppEvent> > .Ignored, eventName, ruleConfig.Action)) .Returns((actionDescription, actionData)); var job = sut.CreateJob(ruleConfig, ruleEnvelope); Assert.Null(job); }
public void Should_set_next_attempt_based_on_num_calls(int calls, int minutes, RuleResult result, RuleJobResult jobResult) { var actionData = new RuleJobData(); var actionName = "MyAction"; var @event = CreateEvent(calls, actionName, actionData); var requestElapsed = TimeSpan.FromMinutes(1); var requestDump = "Dump"; SetupSender(@event, requestDump, result, requestElapsed); SetupPendingEvents(@event); var sut = new RuleDequeuer( ruleService, ruleEventRepository, log, clock); sut.Next(); sut.Dispose(); Instant?nextCall = null; if (minutes > 0) { nextCall = now.Plus(Duration.FromMinutes(minutes)); } VerifyRepositories(@event, requestDump, result, jobResult, requestElapsed, nextCall); }
public async Task Should_set_next_attempt_based_on_num_calls(int calls, int minutes, RuleResult result, RuleJobResult jobResult) { var actionData = new RuleJobData(); var actionName = "MyAction"; var @event = CreateEvent(calls, actionName, actionData); var requestElapsed = TimeSpan.FromMinutes(1); var requestDump = "Dump"; A.CallTo(() => ruleService.InvokeAsync(@event.Job.ActionName, @event.Job.ActionData)) .Returns((requestDump, result, requestElapsed)); Instant?nextCall = null; if (minutes > 0) { nextCall = now.Plus(Duration.FromMinutes(minutes)); } await sut.HandleAsync(@event); A.CallTo(() => ruleEventRepository.MarkSentAsync(@event.Id, requestDump, result, jobResult, requestElapsed, nextCall)) .MustHaveHappened(); }
public async Task Should_create_exception_details_when_job_to_execute_failed() { var ruleJob = new RuleJobData(); var ruleEx = new InvalidOperationException(); A.CallTo(() => ruleActionHandler.ExecuteJobAsync(ruleJob)) .Throws(ruleEx); var result = await sut.InvokeAsync("WebhookAction", ruleJob); Assert.Equal((ruleEx.ToString(), RuleResult.Failed, TimeSpan.Zero), result); }
protected override (string Description, RuleJobData Data) CreateJob(Envelope <AppEvent> @event, string eventName, SlackAction action) { var body = CreatePayload(@event, action.Text); var ruleDescription = "Send message to slack"; var ruleData = new RuleJobData { ["RequestUrl"] = action.WebhookUrl, ["RequestBody"] = body }; return(ruleDescription, ruleData); }
protected override (string Description, RuleJobData Data) CreateJob(Envelope <AppEvent> @event, string eventName, WebhookAction action) { var body = formatter.ToRouteData(@event, eventName); var signature = $"{body.ToString(Formatting.Indented)}{action.SharedSecret}".Sha256Base64(); var ruleDescription = $"Send event to webhook '{action.Url}'"; var ruleData = new RuleJobData { ["RequestUrl"] = action.Url, ["RequestBody"] = body, ["RequestSignature"] = signature }; return(ruleDescription, ruleData); }
protected override (string Description, RuleJobData Data) CreateJob(Envelope <AppEvent> @event, string eventName, FastlyAction action) { var ruleDescription = "Purge key in fastly"; var ruleData = new RuleJobData { ["FastlyApiKey"] = action.ApiKey, ["FastlyServiceID"] = action.ServiceId }; if (@event.Headers.Contains(CommonHeaders.AggregateId)) { ruleData["Key"] = @event.Headers.AggregateId().ToString(); } return(ruleDescription, ruleData); }
public async Task Should_return_failed_job_with_full_dump_when_handler_returns_exception() { var ruleJob = new RuleJobData(); var ruleEx = new InvalidOperationException(); var actionDump = "MyDump"; A.CallTo(() => ruleActionHandler.ExecuteJobAsync(ruleJob)) .Returns((actionDump, new InvalidOperationException())); var result = await sut.InvokeAsync("WebhookAction", ruleJob); Assert.Equal(RuleResult.Failed, result.Result); Assert.True(result.Elapsed >= TimeSpan.Zero); Assert.True(result.Dump.StartsWith(actionDump, StringComparison.OrdinalIgnoreCase)); }
public void Should_create_job_if_triggered() { var e = new ContentCreated { SchemaId = new NamedId <Guid>(Guid.NewGuid(), "my-schema"), AppId = new NamedId <Guid>(Guid.NewGuid(), "my-event") }; var now = SystemClock.Instance.GetCurrentInstant(); var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); var ruleEnvelope = Envelope.Create(e); ruleEnvelope.SetTimestamp(now); var actionName = "WebhookAction"; var actionData = new RuleJobData(); var actionDescription = "MyDescription"; var eventName = "MySchemaCreatedEvent"; A.CallTo(() => clock.GetCurrentInstant()) .Returns(now); A.CallTo(() => ruleTriggerHandler.Triggers(A <Envelope <AppEvent> > .Ignored, ruleConfig.Trigger)) .Returns(true); A.CallTo(() => ruleActionHandler.CreateJob(A <Envelope <AppEvent> > .Ignored, eventName, ruleConfig.Action)) .Returns((actionDescription, actionData)); var job = sut.CreateJob(ruleConfig, ruleEnvelope); Assert.Equal(eventName, job.EventName); Assert.Equal(actionData, job.ActionData); Assert.Equal(actionName, job.ActionName); Assert.Equal(actionDescription, job.Description); Assert.Equal(now, job.Created); Assert.Equal(now.Plus(Duration.FromDays(2)), job.Expires); Assert.Equal(e.AppId.Id, job.AppId); Assert.NotEqual(Guid.Empty, job.JobId); }
private IRuleEventEntity CreateEvent(int numCalls, string actionName, RuleJobData actionData) { var @event = A.Fake <IRuleEventEntity>(); var job = new RuleJob { RuleId = Guid.NewGuid(), ActionData = actionData, ActionName = actionName, Created = now }; A.CallTo(() => @event.Id).Returns(Guid.NewGuid()); A.CallTo(() => @event.Job).Returns(job); A.CallTo(() => @event.Created).Returns(now); A.CallTo(() => @event.NumCalls).Returns(numCalls); return(@event); }
public virtual async Task <(string Dump, RuleResult Result, TimeSpan Elapsed)> InvokeAsync(string actionName, RuleJobData job) { try { var actionType = typeNameRegistry.GetType(actionName); var actionWatch = Stopwatch.StartNew(); var result = await ruleActionHandlers[actionType].ExecuteJobAsync(job); actionWatch.Stop(); var dumpBuilder = new StringBuilder(result.Dump); dumpBuilder.AppendLine(); dumpBuilder.AppendFormat("Elapsed {0}.", actionWatch.Elapsed); dumpBuilder.AppendLine(); if (result.Exception is TimeoutException || result.Exception is OperationCanceledException) { dumpBuilder.AppendLine(); dumpBuilder.AppendLine("Action timed out."); return(dumpBuilder.ToString(), RuleResult.Timeout, actionWatch.Elapsed); } else if (result.Exception != null) { return(dumpBuilder.ToString(), RuleResult.Failed, actionWatch.Elapsed); } else { return(dumpBuilder.ToString(), RuleResult.Success, actionWatch.Elapsed); } } catch (Exception ex) { return(ex.ToString(), RuleResult.Failed, TimeSpan.Zero); } }
public override async Task <(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job) { var requestBody = job["RequestBody"].ToString(Formatting.Indented); var requestMsg = BuildRequest(job, requestBody); HttpResponseMessage response = null; try { response = await HttpClientPool.GetHttpClient().SendAsync(requestMsg); var responseString = await response.Content.ReadAsStringAsync(); var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, responseString, TimeSpan.Zero, false); Exception ex = null; if (!response.IsSuccessStatusCode) { ex = new HttpRequestException($"Response code does not indicate success: {(int)response.StatusCode} ({response.StatusCode})."); } return(requestDump, ex); } catch (Exception ex) { if (requestMsg != null) { var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, ex.ToString(), TimeSpan.Zero, false); return(requestDump, ex); } else { throw; } } }
public override async Task <(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job) { if (!job.TryGetValue("Key", out var keyToken)) { return(null, new InvalidOperationException("The action cannot handle this event.")); } var requestMsg = BuildRequest(job, keyToken.Value <string>()); HttpResponseMessage response = null; try { response = await HttpClientPool.GetHttpClient().SendAsync(requestMsg); var responseString = await response.Content.ReadAsStringAsync(); var requestDump = DumpFormatter.BuildDump(requestMsg, response, null, responseString, TimeSpan.Zero, false); return(requestDump, null); } catch (Exception ex) { if (requestMsg != null) { var requestDump = DumpFormatter.BuildDump(requestMsg, response, null, ex.ToString(), TimeSpan.Zero, false); return(requestDump, ex); } else { var requestDump = ex.ToString(); return(requestDump, ex); } } }
public override async Task <(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job) { var requestBody = job["RequestBody"].ToString(Formatting.Indented); var request = BuildRequest(job, requestBody); HttpResponseMessage response = null; try { using (var client = new HttpClient { Timeout = Timeout }) { response = await client.SendAsync(request); var responseString = await response.Content.ReadAsStringAsync(); var requestDump = DumpFormatter.BuildDump(request, response, requestBody, responseString, TimeSpan.Zero, false); return(requestDump, null); } } catch (Exception ex) { if (request != null) { var requestDump = DumpFormatter.BuildDump(request, response, requestBody, ex.ToString(), TimeSpan.Zero, false); return(requestDump, ex); } else { var requestDump = ex.ToString(); return(requestDump, ex); } } }
public override async Task <(string Dump, Exception Exception)> ExecuteJobAsync(RuleJobData job) { var requestBody = job["RequestBody"].ToString(Formatting.Indented); var requestMsg = BuildRequest(job, requestBody); HttpResponseMessage response = null; try { response = await HttpClientPool.GetHttpClient().SendAsync(requestMsg); var responseString = await response.Content.ReadAsStringAsync(); var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, responseString, TimeSpan.Zero, false); return(requestDump, null); } catch (Exception ex) { if (requestMsg != null) { var requestDump = DumpFormatter.BuildDump(requestMsg, response, requestBody, ex.ToString(), TimeSpan.Zero, false); return(requestDump, ex); } else { throw; } } }