public void PipelineBuilder_BuildFromConfiguration_AssemblyServices_MultiAvailable() { var element = new ElementOptions() { BuilderName = "RequiredService" }; // Create configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; var service = new RequiredServiceElementBuilder.EmptyService(); var httpClient = new Mock <HttpClient>(); var updateService = new DataUpdateService( new Mock <ILogger <DataUpdateService> >().Object, httpClient.Object); var services = new FiftyOneServiceProvider(); services.AddService(service); services.AddService(updateService); // Pass the configuration to the builder to create the pipeline. var pipeline = new PipelineBuilder(_loggerFactory, services) .BuildFromConfiguration(opts); Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().LoggerFactory); Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().Service); Assert.AreEqual(service, pipeline.GetElement <RequiredServiceElement>().Service); Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().UpdateService); Assert.AreEqual(updateService, pipeline.GetElement <RequiredServiceElement>().UpdateService); }
public void PipelineBuilder_BuildFromConfiguration_NotInServiceCollection() { var element = new ElementOptions() { BuilderName = "MultiplyByElementBuilder" }; element.BuildParameters.Add("multiple", "3"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; _maxErrors = 1; Mock <IServiceProvider> services = new Mock <IServiceProvider>(); services.Setup(s => s.GetService(typeof(MultiplyByElementBuilder))) .Returns(null); // Pass the configuration to the builder to create the pipeline. var pipeline = new PipelineBuilder(_loggerFactory, services.Object) .BuildFromConfiguration(opts); }
/// <summary> /// Ensure the json and javascript elements are added to the configuration /// </summary> /// <param name="options"></param> private static void AddJsElements(PipelineOptions options) { var jsonConfig = options.Elements.Where(e => e.BuilderName.Contains(nameof(JsonBuilderElement), StringComparison.OrdinalIgnoreCase)); var javascriptConfig = options.Elements.Where(e => e.BuilderName.Contains(nameof(JavaScriptBuilderElement), StringComparison.OrdinalIgnoreCase)); var jsIndex = javascriptConfig.Any() ? options.Elements.IndexOf(javascriptConfig.First()) : -1; if (jsonConfig.Any() == false) { // The json builder is not included so add it. var newElementOptions = new ElementOptions() { BuilderName = nameof(JsonBuilderElement) }; if (jsIndex > -1) { // There is already a javascript builder element // so insert the json builder before it. options.Elements.Insert(jsIndex, newElementOptions); } else { options.Elements.Add(newElementOptions); } } if (jsIndex == -1) { // The builder is not included so add it. options.Elements.Add(new ElementOptions() { BuilderName = nameof(JavaScriptBuilderElement), BuildParameters = new Dictionary <string, object>() { { "EndPoint", "/51dpipeline/json" } } }); } else { // There is already a JavaScript builder config so check if // the endpoint is specified. If not, add it. if (javascriptConfig.Single().BuildParameters.ContainsKey("EndPoint") == false) { javascriptConfig.Single().BuildParameters.Add("EndPoint", "/51dpipeline/json"); } } }
public void PipelineBuilder_BuildFromConfiguration_ParallelElements() { var multiplyElement = new ElementOptions() { BuilderName = "MultiplyByElement" }; multiplyElement.BuildParameters.Add("Multiple", "3"); // Create the element that holds the elements that // will be run in parallel. var parentElement = new ElementOptions() { }; parentElement.SubElements.Add(new ElementOptions() { BuilderName = "ListSplitterElement" }); parentElement.SubElements.Add(multiplyElement); // Create the configuration object. PipelineOptions options = new PipelineOptions(); options.Elements = new List <ElementOptions> { parentElement }; // Pass the configuration to the builder to create the pipeline. var pipeline = _builder.BuildFromConfiguration(options); // Get the elements var splitterElement = pipeline.GetElement <ListSplitterElement>(); var multiplyByElement = pipeline.GetElement <MultiplyByElement>(); // Create, populate and process flow data. using (var flowData = pipeline.CreateFlowData()) { flowData .AddEvidence(splitterElement.EvidenceKeys[0], "1,2,abc") .AddEvidence(multiplyByElement.EvidenceKeys[0], 25) .Process(); // Get the results and verify them. var splitterData = flowData.GetFromElement(splitterElement); var multiplyByData = flowData.GetFromElement(multiplyByElement); Assert.AreEqual("1", splitterData.Result[0]); Assert.AreEqual("2", splitterData.Result[1]); Assert.AreEqual("abc", splitterData.Result[2]); Assert.AreEqual(75, multiplyByData.Result); } }
/// <summary> /// Create a <see cref="ParallelElements"/> from the specified /// configuration and add it to the _flowElements list. /// </summary> /// <param name="elements"> /// The list to add the new <see cref="ParallelElements"/> to. /// </param> /// <param name="elementOptions"> /// The <see cref="ElementOptions"/> instance to use when creating /// the <see cref="ParallelElements"/>. /// </param> /// <param name="elementIndex"> /// The index of the element within the <see cref="PipelineOptions"/>. /// </param> private void AddParallelElementsToList( List <IFlowElement> elements, ElementOptions elementOptions, int elementIndex) { // Element contains further sub elements, this is not allowed. if (string.IsNullOrEmpty(elementOptions.BuilderName) == false || (elementOptions.BuildParameters != null && elementOptions.BuildParameters.Count > 0)) { throw new PipelineConfigurationException( $"ElementOptions {elementIndex} contains both " + $"SubElements and other settings values. " + $"This is invalid"); } List <IFlowElement> parallelElements = new List <IFlowElement>(); // Iterate through the sub elements, creating them and // adding them to the list. int subCounter = 0; foreach (var subElement in elementOptions.SubElements) { if (subElement.SubElements != null && subElement.SubElements.Count > 0) { throw new PipelineConfigurationException( $"ElementOptions {elementIndex} contains nested " + $"sub elements. This is not supported."); } else { AddElementToList(parallelElements, subElement, $"element {subCounter} in element {elementIndex}"); } subCounter++; } // Now we've created all the elements, create the // ParallelElements instance and add it to the pipeline's // elements. var parallelInstance = new ParallelElements( LoggerFactory.CreateLogger <ParallelElements>(), parallelElements.ToArray()); elements.Add(parallelInstance); }
public void PipelineBuilder_BuildFromConfiguration_ClassNameAlternate() { var element = new ElementOptions() { BuilderName = "Multiply" }; element.BuildParameters.Add("multiple", "8"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; VerifyMultiplyByElementPipeline(opts); }
public void PipelineBuilder_BuildFromConfiguration_ListFromStringSingleEntry() { var element = new ElementOptions() { BuilderName = "ListSplitterElement" }; element.BuildParameters.Add("Delimiters", "|"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; VerifyListSplitterElementPipeline(opts, SplitOption.Pipe); }
public void PipelineBuilder_BuildFromConfiguration_MethodNameAlternate() { var element = new ElementOptions() { BuilderName = "ListSplitterElement" }; element.BuildParameters.Add("delim", "|"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; VerifyListSplitterElementPipeline(opts, SplitOption.Pipe); }
public void PipelineBuilder_BuildFromConfiguration_OptionalMethodInteger() { var element = new ElementOptions() { BuilderName = "ListSplitterElement" }; element.BuildParameters.Add("MaxLength", "3"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; VerifyListSplitterElementPipeline(opts, SplitOption.CommaMaxLengthThree); }
public void PipelineBuilder_BuildFromConfiguration_SingleMandatoryParameter() { // Create the configuration object. var element = new ElementOptions() { BuilderName = "MultiplyByElementBuilder" }; element.BuildParameters.Add("multiple", "8"); PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; VerifyMultiplyByElementPipeline(opts); }
public void PipelineBuilder_BuildFromConfiguration_NoBuilder() { var element = new ElementOptions() { BuilderName = "NoBuilder" }; // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; _maxErrors = 1; // Pass the configuration to the builder to create the pipeline. var pipeline = _builder.BuildFromConfiguration(opts); }
public void PipelineBuilder_BuildFromConfiguration_ServiceCollection() { var element = new ElementOptions() { BuilderName = "MultiplyByElementBuilder" }; element.BuildParameters.Add("multiple", "3"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; Mock <IServiceProvider> services = new Mock <IServiceProvider>(); services.Setup(s => s.GetService(typeof(MultiplyByElementBuilder))) .Returns(new MultiplyByElementBuilder()); // Pass the configuration to the builder to create the pipeline. var pipeline = new PipelineBuilder(_loggerFactory, services.Object) .BuildFromConfiguration(opts); // Get the element var multiplyByElement = pipeline.GetElement <MultiplyByElement>(); // Create, populate and process flow data. using (var flowData = pipeline.CreateFlowData()) { flowData .AddEvidence(multiplyByElement.EvidenceKeys[0], 25) .Process(); // Get the results and verify them. var multiplyByData = flowData.GetFromElement(multiplyByElement); Assert.AreEqual(75, multiplyByData.Result); } }
public void PipelineBuilder_BuildFromConfiguration_OptionalMethodWrongType() { var element = new ElementOptions() { BuilderName = "ListSplitterElement" }; element.BuildParameters.Add("MaxLength", "WrongType"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; _maxErrors = 1; VerifyListSplitterElementPipeline(opts, SplitOption.Comma); }
public void PipelineBuilder_BuildFromConfiguration_MandatoryParameterWrongType() { var element = new ElementOptions() { BuilderName = "MultiplyByElementBuilder" }; element.BuildParameters.Add("multiple", "WrongType"); // Create the configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; _maxErrors = 1; // Pass the configuration to the builder to create the pipeline. var pipeline = _builder.BuildFromConfiguration(opts); }
public void PipelineBuilder_BuildFromConfiguration_AssemblyServices_NotAvailable() { var element = new ElementOptions() { BuilderName = "RequiredService" }; // Create configuration object. PipelineOptions opts = new PipelineOptions(); opts.Elements = new List <ElementOptions> { element }; // Pass the configuration to the builder to create the pipeline. var pipeline = new PipelineBuilder(_loggerFactory, new FiftyOneServiceProvider()) .BuildFromConfiguration(opts); Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().LoggerFactory); Assert.IsNull(pipeline.GetElement <RequiredServiceElement>().Service); Assert.IsNull(pipeline.GetElement <RequiredServiceElement>().UpdateService); }
private static bool WaitHandler(IWebElement e, int timeout, ElementOptions option, string text = "") { var watch = new Stopwatch(); var driver = WebDriverSupport.SupportDriver(); var result = false; watch.Start(); driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0); while (watch.Elapsed.TotalMilliseconds <= timeout.ToMilliseconds() && !result) { try { switch (option) { case ElementOptions.Displayed: if (e.Displayed) { result = true; } break; case ElementOptions.NotDisplayed: if (e == null || !e.Displayed) { result = true; } break; case ElementOptions.Enabled: if (e.Enabled) { result = true; } break; case ElementOptions.SelectOptionDisplayed: if (e.FindElements(By.TagName("option")).Count(x => x.Text.Contains(text)) > 0) { result = true; } break; default: throw new ArgumentOutOfRangeException(nameof(option), option, null); } } catch (NoSuchElementException) { if (option == ElementOptions.NotDisplayed) { result = true; } } catch (StaleElementReferenceException) { if (option == ElementOptions.NotDisplayed) { result = true; } } catch { //Ignored } } // if (watch.Elapsed.Seconds > 1) Log.Info($"Waited for {watch.Elapsed.Seconds} seconds for the element state {option}"); return(result); }
/// <summary> /// Private constructor used to construct the only instance which will /// exist of this class. /// </summary> private WebPipeline() { IConfiguration config = new ConfigurationBuilder() .AddPipelineConfig() .Build(); _options = new PipelineWebIntegrationOptions(); config.Bind("PipelineOptions", _options); if (_options == null || _options.Elements == null) { throw new PipelineConfigurationException( Messages.ExceptionNoConfiguration); } // Add the sequence element. var sequenceConfig = _options.Elements.Where(e => e.BuilderName.IndexOf(nameof(SequenceElement), StringComparison.OrdinalIgnoreCase) >= 0); if (sequenceConfig.Any() == false) { // The sequence element is not included so add it. // Make sure it's added as the first element. _options.Elements.Insert(0, new ElementOptions() { BuilderName = nameof(SequenceElement) }); } if (ClientSideEvidenceEnabled) { // Client-side evidence is enabled so make sure the // JsonBuilderElement and JavaScriptBundlerElement has been // included. var jsonConfig = _options.Elements.Where(e => e.BuilderName.StartsWith(nameof(JsonBuilderElement), StringComparison.OrdinalIgnoreCase)); var javascriptConfig = _options.Elements.Where(e => e.BuilderName.StartsWith(nameof(JavaScriptBuilderElement), StringComparison.OrdinalIgnoreCase)); var jsIndex = javascriptConfig.Any() ? _options.Elements.IndexOf(javascriptConfig.First()) : -1; if (jsonConfig.Any() == false) { // The json builder is not included so add it. var newElementOptions = new ElementOptions() { BuilderName = nameof(JsonBuilderElement) }; if (jsIndex > -1) { // There is already a javascript builder element // so insert the json builder before it. _options.Elements.Insert(jsIndex, newElementOptions); } else { _options.Elements.Add(newElementOptions); } } if (jsIndex == -1) { // The javascript builder is not included so add it. _options.Elements.Add(new ElementOptions() { BuilderName = nameof(JavaScriptBuilderElement), BuildParameters = new Dictionary<string, object>() { { "EndPoint", "/51dpipeline/json" } } }); } else { // There is already a JavaScript builder config so check if // the endpoint is specified. If not, add it. if (javascriptConfig.Single().BuildParameters.ContainsKey("EndPoint") == false) { javascriptConfig.Single().BuildParameters.Add("EndPoint", "/51dpipeline/json"); } } } // Add the set headers var setHeadersConfig = _options.Elements.Where(e => e.BuilderName.IndexOf(nameof(SetHeadersElement), StringComparison.OrdinalIgnoreCase) >= 0); if (setHeadersConfig.Any() == false) { // The set headers element is not included, so add it. // Make sure it's added as the last element. _options.Elements.Add(new ElementOptions() { BuilderName = nameof(SetHeadersElement) }); } // Set up common services. var loggerFactory = new LoggerFactory(); var updateService = new DataUpdateService( loggerFactory.CreateLogger<DataUpdateService>(), new System.Net.Http.HttpClient()); var services = new FiftyOneServiceProvider(); // Add data update and missing property services. services.AddService(updateService); services.AddService(MissingPropertyService.Instance); Pipeline = new PipelineBuilder( loggerFactory, services) .BuildFromConfiguration(_options); }
/// <summary> /// The default <see cref="IPipeline"/> factory function. /// This looks for a 'PipelineOptions' configuration item and uses /// that to build the pipeline. /// </summary> /// <param name="config"> /// The application configuration object /// </param> /// <param name="pipelineBuilder"> /// a pipeline builder instance to use when constructing the /// <see cref="IPipeline"/>. /// </param> /// <returns> /// A new <see cref="IPipeline"/> instance /// </returns> private static IPipeline CreatePipelineFromConfig( IConfiguration config, IPipelineBuilderFromConfiguration pipelineBuilder) { // Get Pipeline options to check that it is present PipelineOptions options = new PipelineOptions(); config.Bind("PipelineOptions", options); if (options == null || options.Elements == null || options.Elements.Count == 0) { throw new PipelineConfigurationException( Messages.ExceptionNoConfiguration); } PipelineWebIntegrationOptions webOptions = new PipelineWebIntegrationOptions(); config.Bind("PipelineWebIntegrationOptions", webOptions); // Add the sequence element. var sequenceConfig = options.Elements.Where(e => e.BuilderName.Contains(nameof(SequenceElement), StringComparison.OrdinalIgnoreCase)); if (sequenceConfig.Any() == false) { // The sequence element is not included so add it. // Make sure it's added as the first element. options.Elements.Insert(0, new ElementOptions() { BuilderName = nameof(SequenceElement) }); } if (webOptions.ClientSideEvidenceEnabled) { // Client-side evidence is enabled so make sure the // JsonBuilderElement and JavaScriptBundlerElement has been // included. var jsonConfig = options.Elements.Where(e => e.BuilderName.Contains(nameof(JsonBuilderElement), StringComparison.OrdinalIgnoreCase)); var javascriptConfig = options.Elements.Where(e => e.BuilderName.Contains(nameof(JavaScriptBuilderElement), StringComparison.OrdinalIgnoreCase)); var jsIndex = javascriptConfig.Any() ? options.Elements.IndexOf(javascriptConfig.First()) : -1; if (jsonConfig.Any() == false) { // The json builder is not included so add it. var newElementOptions = new ElementOptions() { BuilderName = nameof(JsonBuilderElement) }; if (jsIndex > -1) { // There is already a javascript builder element // so insert the json builder before it. options.Elements.Insert(jsIndex, newElementOptions); } else { options.Elements.Add(newElementOptions); } } if (jsIndex == -1) { // The builder is not included so add it. options.Elements.Add(new ElementOptions() { BuilderName = nameof(JavaScriptBuilderElement), BuildParameters = new Dictionary <string, object>() { { "EnableCookies", true } } }); } } return(pipelineBuilder.BuildFromConfiguration(options)); }
/// <summary> /// Create a new <see cref="IFlowElement"/> using the specified /// <see cref="ElementOptions"/> and add it to the supplied list /// of elements. /// </summary> /// <param name="elements"> /// The list to add the new <see cref="IFlowElement"/> to. /// </param> /// <param name="elementOptions"> /// The <see cref="ElementOptions"/> instance to use when creating /// the <see cref="IFlowElement"/>. /// </param> /// <param name="elementLocation"> /// The string description of the element's location within the /// <see cref="PipelineOptions"/> instance. /// </param> private void AddElementToList( List <IFlowElement> elements, ElementOptions elementOptions, string elementLocation) { // Check that a builder name is set if (string.IsNullOrEmpty(elementOptions.BuilderName)) { throw new PipelineConfigurationException( $"A BuilderName must be specified for " + $"{elementLocation}."); } // Try to get the builder to use var builderType = GetBuilderType(elementOptions.BuilderName); if (builderType == null) { throw new PipelineConfigurationException( $"Could not find builder matching " + $"'{elementOptions.BuilderName}' for " + $"{elementLocation}. Available builders are: " + $"{string.Join(",", _elementBuilders.Select(t => t.Name))}"); } // Get the methods on the builder var buildMethods = builderType.GetRuntimeMethods() .Where(m => m.Name == "Build"); // If there are no 'Build' methods or if there is no default // constructor then throw an error. if (buildMethods.Any() == false) { throw new PipelineConfigurationException( $"Builder '{builderType.FullName}' for " + $"{elementLocation} has no 'Build' methods."); } object builderInstance = null; if (_services != null) { // Try to get a a builder instance from the service collection. builderInstance = _services.GetRequiredService(builderType); } else { // A service collection does not exist in the builder, so try // to construct a builder instance from the assemblies // currently loaded. builderInstance = GetBuilderFromAssemlies(builderType); if (builderInstance == null) { throw new PipelineConfigurationException( $"Builder '{builderType.FullName}' for " + $"{elementLocation} does not have a default constructor. " + $"i.e. One that takes no parameters. Or a constructor " + $"which takes an ILoggerFactory parameter."); } } // Holds a list of the names of parameters to pass to the // build method when we're ready. List <string> buildParameterList = new List <string>(); if (elementOptions.BuildParameters != null) { // Call any non-build methods on the builder to set optional // parameters. buildParameterList = ProcessBuildParameters( elementOptions.BuildParameters, builderType, builderInstance, elementLocation); } // At this point, all the optional methods on the builder // have been called and we're ready to call the Build method. // If there are no matching build methods or multiple possible // build methods based on our parameters then throw an exception. var possibleBuildMethods = buildMethods.Where(m => m.GetParameters().Length == buildParameterList.Count && m.GetParameters().All(p => buildParameterList.Contains(p.Name.ToUpperInvariant()))); StringBuilder buildSignatures = new StringBuilder(); buildSignatures.AppendLine(); foreach (var method in buildMethods) { buildSignatures.AppendLine(string.Join(",", method.GetParameters().Select(p => $"{p.Name} ({p.ParameterType.Name})"))); } if (possibleBuildMethods.Any() == false) { StringBuilder methodSignatures = new StringBuilder(); methodSignatures.AppendLine(); // Build a list of the 'set' methods on this builder // along with their parameter. foreach (var method in builderType.GetRuntimeMethods() // Include any methods that are: // 1. public // 2. have a single parameter .Where(m => m.IsPublic && m.GetParameters().Length == 1 && m.DeclaringType.Name.ToUpperInvariant().Contains("BUILDER"))) { methodSignatures.AppendLine($"{method.Name} ({method.GetParameters()[0].GetType().Name})"); } throw new PipelineConfigurationException( $"Builder '{builderType.FullName}' for " + $"{elementLocation} has no " + $"'Set' methods or 'Build' methods that match " + $"(case-insensitively) the following parameters: " + $"{string.Join(",", buildParameterList)}. " + $"The available configuration methods on this builder are: " + $"{methodSignatures.ToString()}" + $"The available 'Build' methods have the following signatures: " + $"{buildSignatures.ToString()}"); } else if (possibleBuildMethods.Count() > 1) { throw new PipelineConfigurationException( $"Builder '{builderType.FullName}' for " + $"{elementLocation} has multiple " + $"'Build' methods that match the following parameters: " + $"{string.Join(",", buildParameterList)}. " + $"Matching method signatures are: {buildSignatures.ToString()}"); } // Get the build method parameters and add the configured // values to the parameter list. List <object> parameters = new List <object>(); var buildMethod = possibleBuildMethods.Single(); var caseInsensitiveParameters = elementOptions.BuildParameters .ToDictionary(d => d.Key.ToUpperInvariant(), d => d.Value); foreach (var parameterInfo in buildMethod.GetParameters()) { var paramType = parameterInfo.ParameterType; object paramValue = caseInsensitiveParameters[parameterInfo.Name.ToUpperInvariant()]; if (paramType != typeof(string)) { paramValue = ParseToType(paramType, (string)paramValue, $"Method 'Build' on builder " + $"'{builderType.FullName}' for " + $"{elementLocation} expects a parameter of type " + $"'{paramType.Name}'"); } parameters.Add(paramValue); } // Call the build method with the parameters we set up above. object result = buildMethod.Invoke(builderInstance, parameters.ToArray()); if (result == null) { throw new PipelineConfigurationException( $"Failed to build {elementLocation} using " + $"'{builderType.FullName}', reason unknown."); } IFlowElement element = result as IFlowElement; if (element == null) { throw new PipelineConfigurationException( $"Failed to cast '{result.GetType().FullName}' to " + $"'IFlowElement' for {elementLocation}"); } // Add the element to the list. elements.Add(element); }
public void AddElement(NoteOption child) { child.Parent = this; ElementOptions.Add(child); }