public void CalculateExecutionTimeoutDateTimeUtc_GivenExecutionRequestWithoutTimeoutDuration_ShouldReturnDateTimeBasedOnDefaultTimeoutDuration() { var execRequest = new ExecutionRequest { ExecutionId = Guid.NewGuid().ToString() }; execRequest.CalculateExecutionTimeoutDateTimeUtc(TimeSpan.FromHours(2)); execRequest.ExecutionTimeoutDateTimeUtc.Should().BeAfter(DateTime.UtcNow.AddHours(2).AddSeconds(-5)).And .BeBefore(DateTime.UtcNow.AddHours(2).AddSeconds(5)); }
public async Task <Core.Models.ExecutionContext> ExecuteAsync(ExecutionRequest execRequest, CancellationToken cancelToken) { if (execRequest == null) { throw new ArgumentNullException(nameof(execRequest)); } logger.LogInformation($"Processing execution request [{execRequest.ExecutionId}]..."); // Give all the applicable extension services a chance to do any synchronous pre-work ahead of the actual execution... // For more information on extension services, see /doc/architecture/extension-services.md. await(execRequest.ValidateOnly ? this.execServiceProvider.OnValidatingAsync(execRequest) : this.execServiceProvider.OnExecutingAsync(execRequest)); // UTC now + the execution timeout on the execution request if it was provided. // If no execution timeout was defined, default to an hour [defaultTimeoutPeriod]. execRequest.CalculateExecutionTimeoutDateTimeUtc(defaultTimeoutPeriod); logger.LogDebug($"Execution [{execRequest.ExecutionId}] timeout set to [{execRequest.ExecutionTimeoutDateTimeUtc}] UTC."); // We're about to execution the extension. Create an execution context to capture the results... var execContext = execRequest.ToExecutionContext(); try { // Deserialize the execution model-specific settings, provided in the [execRequest.extensionSettings] JSON object property, // to get the execution and/or validation URLs that we need to handle the request. var httpSettings = GetHttpExtensionSettings(execRequest); // Create the execution request that we'll POST to the extension... var httpExecRequest = await ToHttpExecutionRequestAsync(execRequest); logger.LogDebug($"Execution [{execRequest.ExecutionId}] URL is [{httpSettings.ExecutionUrl}]."); logger.LogDebug(string.IsNullOrEmpty(httpSettings.ValidationUrl) ? $"Execution [{execRequest.ExecutionId}] validation URL is [{httpSettings.ValidationUrl}]." : $"Execution [{execRequest.ExecutionId}] validation URL not provided."); // If there was a valid RSA public/private key pair provided along with the request, // sign the request before we send it along to the extension... if (!string.IsNullOrEmpty(execRequest.SignatureRsaKeyXml)) { logger.LogDebug($"Signing execution request [{execRequest.ExecutionId}]..."); httpExecRequest.Signature = await httpExecRequestSigner.GenerateSignatureAsync(execRequest.SignatureRsaKeyXml, httpExecRequest); } if (execRequest.ValidateOnly) { // If it's a validation only request, make sure that the extension actually supports validation. // Under normal circumstances, this should have been caught way further upstream at the execution API. if (execRequest.IsValidationSupported == false) { throw new NotSupportedException($"Extension [{execRequest.ExtensionId}:{execRequest.ExtensionVersionId}] " + "does not support validation."); } // Validate the request... execContext = await ValidateAsync(execContext, httpExecRequest, httpSettings); } else { // Execute the request... execContext = await ExecuteAsync(execContext, httpExecRequest, httpSettings); } } catch (Exception ex) { logger.LogError($"An error occurred while processing execution request [{execRequest.ExecutionId}]: [{ex.Message}]."); execContext.UpdateStatus(ExecutionStatus.Failed); } finally { // Give all the applicable extension services a chance to do any synchronous post-work after the execution // regardless of whether or not it succeeded. For more information on extension services, see /doc/architecture/extension-services.md. await(execRequest.ValidateOnly ? this.execServiceProvider.OnValidatedAsync(execContext) : this.execServiceProvider.OnExecutedAsync(execContext)); logger.LogInformation($"Execution request [{execRequest.ExecutionId}] processing complete."); } return(execContext); }