private void ParsePathItemForMetadata(JsonPathFinder pathItem, Dictionary <string, RuntimeTypeData> definitionsCache, Dictionary <string, Dictionary <string, ParameterData> > parameterCache, JsonPathFinder rootDoc) { // Parse path item level parameters first JsonPathFinder pathLevelParameters = pathItem.Find(new JsonQueryBuilder().Property("parameters")).SingleOrDefault(); List <Dictionary <string, ParameterData> > pathLevelParameterList = new List <Dictionary <string, ParameterData> >(); if (pathLevelParameters != null) { foreach (JsonPathFinder parameterNode in pathLevelParameters.Children()) { Dictionary <string, ParameterData> parameters = GetParameterMetadata(parameterNode.Path, parameterNode, definitionsCache, parameterCache, rootDoc); pathLevelParameterList.Add(parameters); } } // Parse each path (all children that are not keyed by "$ref" or "parameters") foreach (JsonPathFinder operationContainerNode in pathItem.Children().Where(n => String.IsNullOrEmpty(n.Key) || (!n.Key.Equals("parameters") && !n.Key.Equals("$ref")))) { // Get parameter metadata from the operation OperationData operationData = ParseOperationForMetadata(operationContainerNode.OpenContainer(), definitionsCache, parameterCache, rootDoc); // Apply the path item level parameter data to this operation if (operationData != null) { Log(String.Format(CultureInfo.InvariantCulture, "Applying path level parameters to operation '{0}'", operationData.OperationId)); foreach (Dictionary <string, ParameterData> parametersSet in pathLevelParameterList) { foreach (string parameterName in parametersSet.Keys) { if (operationData.Parameters.ContainsKey(parameterName.ToLowerInvariant())) { Log(String.Format(CultureInfo.InvariantCulture, "Found parameter with name '{0}' and JSON name '{1}'", parameterName, parametersSet[parameterName].JsonName)); operationData.Parameters[parameterName.ToLowerInvariant()].MergeWith(parametersSet[parameterName]); } } } } } // TODO: Currently no support for path item using $ref }
public virtual CommandExecutionResult ProcessRequest(LiveTestRequest request, LiveTestCredentialFactory credentialsFactory) { if (this.Logger != null) { this.Logger.LogAsync("Translating credentials..."); } credentialsFactory.TranslateCredentialsObjects(request); CommandExecutionResult result = null; string operationId = request.OperationId == null ? null : request.OperationId.ToLowerInvariant(); if (this.Logger != null) { this.Logger.LogAsync("Operation ID of message: " + operationId); } if (!String.IsNullOrEmpty(operationId) && this.Operations.ContainsKey(operationId)) { if (this.Logger != null) { this.Logger.LogAsync("Processing operation..."); } OperationData op = this.Operations[operationId]; // Create the command ICommandBuilder command = this.runspace.CreateCommand(); command.Command = op.Command; foreach (string parameterName in op.Parameters.Keys) { if (request.Params != null && request.Params.ContainsKey(parameterName.ToLowerInvariant())) { command.AddParameter(parameterName, request.Params[parameterName.ToLowerInvariant()]); } else { this.Logger.LogAsync("Request missing parameter: " + parameterName); } } // Process credentials IEnumerable <ICredentialProvider> credProviders = credentialsFactory.Create(request, this.Logger); foreach (ICredentialProvider credProvider in credProviders) { credProvider.Process(command); } // Run the command result = command.Invoke(); // Run post processors, if any foreach (ICommandPostProcessor postProcessor in op.PostProcessors) { result = postProcessor.Process(result); } } else { // error if (this.Logger != null) { this.Logger.LogError("Operation ID was not found in module under test."); } } return(result); }
private OperationData ParseOperationForMetadata(JsonPathFinder path, Dictionary <string, RuntimeTypeData> definitionsCache, Dictionary <string, Dictionary <string, ParameterData> > parameterCache, JsonPathFinder rootDoc) { JsonPathFinder parametersNode = path.Find(new JsonQueryBuilder().Property("parameters")).SingleOrDefault(); JsonPathFinder operationIdNode = path.Find(new JsonQueryBuilder().Property("operationId")).SingleOrDefault(); if (operationIdNode == null) { return(null); } string operationId = operationIdNode.GetValue <string>(); if (!this.Operations.ContainsKey(operationId.ToLowerInvariant())) { Log(String.Format(CultureInfo.InvariantCulture, "Skipping operation '{0}' because no matching command was found.", operationId)); return(null); } OperationData operationData = this.Operations[operationId.ToLowerInvariant()]; Log(String.Format(CultureInfo.InvariantCulture, "Loading metadata for operation '{0}' and command '{1}'", operationId, operationData.Command)); if (parametersNode != null) { foreach (JsonPathFinder parameterNode in parametersNode.Children()) { Dictionary <string, ParameterData> parameters = GetParameterMetadata(parameterNode.Path, parameterNode, definitionsCache, parameterCache, rootDoc); foreach (string parameterName in parameters.Keys) { if (operationData.Parameters.ContainsKey(parameterName.ToLowerInvariant())) { Log(String.Format(CultureInfo.InvariantCulture, "Found parameter with name '{0}' and JSON name '{1}'", parameterName, parameters[parameterName].JsonName)); operationData.Parameters[parameterName.ToLowerInvariant()].MergeWith(parameters[parameterName]); } } } } // Find the first response in the [200-299] range, as that's all PSSwagger supports right now JsonPathFinder responsesNode = path.Find(new JsonQueryBuilder().Property("responses")).SingleOrDefault(); string responseDefinitionPath = null; if (responsesNode != null && operationData.ResponseType != null) { foreach (JsonPathFinder response in responsesNode.Children()) { int statusCode; if (Int32.TryParse(response.Key, out statusCode) && statusCode >= 200 && statusCode <= 299) { // For now we only support ref'd schema - need to fix that JsonPathFinder schemaRefNode = response.Find(new JsonQueryBuilder().RecursiveDescent().Property("$ref")).SingleOrDefault(); if (schemaRefNode != null) { responseDefinitionPath = schemaRefNode.GetValue <string>(); string definitionPathCaseInsensitive = responseDefinitionPath.ToLowerInvariant(); if (definitionsCache.ContainsKey(definitionPathCaseInsensitive)) { operationData.ResponseType.SpecificationData.Add(definitionsCache[definitionPathCaseInsensitive]); break; } } } } } // Check for x-ms-pageable and set the page type if a response type exists JsonPathFinder pageableExtension = path.Find(new JsonQueryBuilder().Property("x-ms-pageable")).SingleOrDefault(); if (pageableExtension != null && operationData.ResponseType != null) { string nextLinkJsonName = "nextLink"; string itemsJsonName = "value"; JsonPathFinder nextLinkName = pageableExtension.Find(new JsonQueryBuilder().RecursiveDescent().Property("nextLinkName")).SingleOrDefault(); JsonPathFinder itemName = pageableExtension.Find(new JsonQueryBuilder().RecursiveDescent().Property("itemName")).SingleOrDefault(); if (nextLinkName != null) { nextLinkJsonName = nextLinkName.GetValue <string>(); } if (itemName != null) { itemsJsonName = itemName.GetValue <string>(); } // Assuming the module is already loaded, find the correct .NET type for the Page foreach (Type candidateType in AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.GetTypes())) { PropertyInfo itemsProperty = candidateType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(pi => pi.Name.Equals("Items")).FirstOrDefault(); PropertyInfo nextPageLinkProperty = candidateType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Where(pi => pi.Name.Equals("NextPageLink")).FirstOrDefault(); bool candidate = true; if (itemsProperty != null) { JsonPropertyAttribute jsonPropertyAttribute = (JsonPropertyAttribute)itemsProperty.GetCustomAttribute(typeof(JsonPropertyAttribute)); if (jsonPropertyAttribute == null || !jsonPropertyAttribute.PropertyName.Equals(itemsJsonName, StringComparison.OrdinalIgnoreCase)) { candidate = false; } } else { candidate = false; } if (candidate && nextPageLinkProperty != null) { JsonPropertyAttribute jsonPropertyAttribute = (JsonPropertyAttribute)nextPageLinkProperty.GetCustomAttribute(typeof(JsonPropertyAttribute)); if (jsonPropertyAttribute == null || !jsonPropertyAttribute.PropertyName.Equals(nextLinkJsonName, StringComparison.OrdinalIgnoreCase)) { candidate = false; } } else { candidate = false; } if (candidate) { operationData.ResponseType.PageType = candidateType; } } // Find the correct specification data. If x-ms-pageable is used, the referenced output type is probably an array of items // And PSSwagger will output the individual item type rather than the array type // Set the output type of the individual item type if (!String.IsNullOrEmpty(responseDefinitionPath)) { JsonPathFinder responseDefinitionNode = rootDoc.Find(new JsonQueryBuilder(responseDefinitionPath)).SingleOrDefault(); if (responseDefinitionNode != null) { JsonPathFinder itemType = responseDefinitionNode.Find(new JsonQueryBuilder().RecursiveDescent().Property("$ref")).FirstOrDefault(); if (itemType != null) { operationData.ResponseType.SpecificationData.Add(definitionsCache[itemType.GetValue <string>().ToLowerInvariant()]); } } } } return(operationData); }