/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; HttpStatusCode? statusCode1 = VerificationHelper.VerifyCanonicalFunction(context, CanonicalFunctionType.Supported, out passed, out info); if (true != passed) { if (info != null) { info.SetDetailsName(this.Name); } return passed; } HttpStatusCode? statusCode2 = VerificationHelper.VerifyCanonicalFunction(context, CanonicalFunctionType.Unsupported, out passed, out info); passed = statusCode2 == HttpStatusCode.NotImplemented ? true : false; if (info != null) { info.SetDetailsName(this.Name); } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } info = null; List<ExtensionRuleResultDetail> details = new List<ExtensionRuleResultDetail>(); ExtensionRuleViolationInfo info1 = null, info2 = null; bool? isVerifySortEntitiesOrderByAsc = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out info1); bool? isVerifySortEntitiesOrderByDesc = VerificationHelper.VerifySortEntities(context, SortedType.DESC, out info2); if (info1 != null) { details.AddRange(info1.Details); } if (info2 != null) { details.AddRange(info2.Details); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); info.SetDetailsName(this.Name); return true == isVerifySortEntitiesOrderByAsc && true == isVerifySortEntitiesOrderByDesc; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; Uri metadataServiceUrl = new Uri(context.Destination.AbsoluteUri.TrimEnd('/') + @"/$metadata" + @"/"); var req = WebRequest.Create(metadataServiceUrl) as HttpWebRequest; Response response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, metadataServiceUrl.AbsoluteUri, "GET", string.Empty, response); if (response != null && response.StatusCode == HttpStatusCode.OK && response.ResponsePayload.IsMetadata()) { passed = true; } else { passed = false; detail.ErrorMessage = "The response is not the metadata service document. Please refer to section 15 of [OData-CSDL]."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; HttpStatusCode? statusCode1 = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } if (true != passed) { return passed; } HttpStatusCode? statusCode2 = VerificationHelper.VerifySortEntities(context, SortedType.DESC, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; var response = WebHelper.Get(context.Destination, string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.Destination.AbsoluteUri, "GET", StringHelper.MergeHeaders(string.Empty, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { if (context.PayloadFormat == RuleEngine.PayloadFormat.JsonLight) { passed = true; } else { passed = false; detail.ErrorMessage = "Get above URI with accept header 'application/json', the response is not JSON format."; } } else { passed = false; detail.ErrorMessage = String.Format("No response returned from above URI with accept header 'application/json'."); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; // Verify the lambda operator "any". HttpStatusCode? statusCode1 = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.Any, out passed, out info); if (true != passed) { if (info != null) { info.SetDetailsName(this.Name); } return passed; } // Verify the lambda operator "all". HttpStatusCode? statusCode2 = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.All, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var restrictions = AnnotationsHelper.GetChangeTracking(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(restrictions.Item1) || null == restrictions.Item2 || !restrictions.Item2.Any() || null == restrictions.Item3 || !restrictions.Item3.Any()) { detail.ErrorMessage = "Cannot find an entity-container or any entity-sets which support the change tracking function."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; } string url = string.Format("{0}/{1}", context.ServiceBaseUri, restrictions.Item1); List<KeyValuePair<string, string>> requestHeaders = new List<KeyValuePair<string,string>>(); foreach (KeyValuePair<string, string> kvp in context.RequestHeaders) { requestHeaders.Add(new KeyValuePair<string, string>(kvp.Key, kvp.Value)); } // Add odata.track-changes preference in request header. KeyValuePair<string, string> prefer = new KeyValuePair<string, string>("Prefer", "odata.track-changes"); requestHeaders.Add(prefer); Response response = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, requestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, requestHeaders), response); if (response != null && !string.IsNullOrEmpty(response.ResponseHeaders)) { string preferHeader = response.ResponseHeaders.GetHeaderValue("Preference-Applied"); if (string.IsNullOrEmpty(preferHeader)) { passed = false; detail.ErrorMessage = "The response header returned by the service does not contain 'odata.track-changes', when request with the header 'Prefer:odata.track-changes'."; } else if (preferHeader.Contains("odata.track-changes")) { passed = true; } } else { passed = false; detail.ErrorMessage = "The service does not support Delta change tracking."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; string selectedName = string.Empty; string functionactionName = "forFunctionAction"; // Use the XPath query language to access the metadata document and get all Namespace and Alias value. XElement metadata = XElement.Parse(context.MetadataDocument); string xpath = @"//*[local-name()='DataServices']/*[local-name()='Schema']"; List<string> appropriateNamespace = MetadataHelper.GetPropertyValues(context, xpath, "Namespace"); // Use the XPath query language to access the metadata document and get all Function names and all Action names. xpath = @"//*[local-name()='EntityContainer']/*[local-name()='FunctionImport']"; List<string> functionImportNames = MetadataHelper.GetPropertyValues(context, xpath, "Name"); xpath = @"//*[local-name()='EntityContainer']/*[local-name()='ActionImport']"; List<string> actionImportNames = MetadataHelper.GetPropertyValues(context, xpath, "Name"); if (!functionImportNames.Contains(functionactionName) && !actionImportNames.Contains(functionactionName)) { selectedName = functionactionName; } else { selectedName = functionactionName + "New"; } string url = string.Format("{0}/?$select={1}.{2}", context.Destination, appropriateNamespace[0], selectedName); var req = WebRequest.Create(url) as HttpWebRequest; var response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, url, "GET", string.Empty, response); if (response != null && response.StatusCode != null) { if (response.StatusCode != HttpStatusCode.OK) { passed = true; } else { passed = false; detail.ErrorMessage = "The OData service MUST fail any request that contains actions or functions that it does not understand."; } } else { passed = false; detail.ErrorMessage = String.Format("No response returned from above URI."); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
/// <summary> /// Verifies whether the payload of current request session complies to the specified RelaxNG schema or not /// </summary> /// <param name="context">Context object representing the current OData interop session</param> /// <param name="result">Output parameter of validation result</param> /// <returns>True if passed; false if failed</returns> public bool Verify(ServiceContext context, out TestResult result) { if (context == null) { throw new ArgumentNullException("context"); } return this.Verify(context.ResponsePayload, out result); }
public SimpleJobPlanner(ServiceContext rootCtx, string formatHint, int maxPayloadSize, string category="core") { this.rootCtx = rootCtx; this.metaResource = rootCtx.DestinationBasePath + "/$metadata"; this.acceptHeaderValue = formatHint.MapFormatToAcceptValue(); this.maxPayloadSize = maxPayloadSize; this.category = category; var payloadFormat = this.rootCtx.ServiceDocument.GetFormatFromPayload(); this.feeds = ContextHelper.GetFeeds(this.rootCtx.ServiceDocument, payloadFormat).ToArray(); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { bool? passed = null; info = null; HttpStatusCode? statusCode = VerificationHelper.VerifyCount(context, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; return passed; }
/// <summary> /// Create a facade view of interop validation engine for the current context /// </summary> /// <param name="context">the current request context object</param> /// <param name="resultProvider">consumer of validation results generated by interop rule engine</param> /// <param name="logger">logger object</param> /// <param name="ruleList">Pre-set rule list</param> public RuleEngineWrapper(ServiceContext context, IResultProvider resultProvider, ILogger logger, List<string> ruleList = null) { this.context = context; this.resultConsumer = resultProvider; this.logger = logger; this.rules = this.context.GetRules().ToList(); if (null != ruleList && ruleList.Count > 0) { this.rules = (from r in this.rules where ruleList.Contains(r.Name) select r).ToList(); } this.categories = (from r in this.rules select r.Category).Distinct().ToList(); }
/// <summary> /// Verifies the specified payload of interop request context against current regular expression rule /// </summary> /// <param name="context">interop request session whose payload is to be verified</param> /// <param name="result">output parameter of verification result</param> /// <returns>true if passed; false if failed</returns> /// <exception cref="ArgumentNullExption">Throws excpetion when context parameter is null</exception> /// <exception cref="ArgumentException">Throws exception when context payload is not of Json</exception> public bool Verify(ServiceContext context, out TestResult result) { if (context == null) { throw new ArgumentNullException("context"); } if (context.PayloadFormat != PayloadFormat.Json && context.PayloadFormat != PayloadFormat.JsonLight) { throw new ArgumentException(Resource.PayloadFormatUnexpected); } return this.Verify(context.ResponsePayload, out result); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); detail.ErrorMessage = @"This negative rule is not verified."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
public new bool Verify(ServiceContext context, out TestResult result) { if (context == null) { throw new ArgumentNullException("context"); } bool passed = this.Verify(context.ResponseHttpHeaders, out result); if (!passed) { result.TextInvolved = this.GetHeaderLineOfName(context.ResponseHttpHeaders); } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; var response = WebHelper.Get(context.Destination, Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.Destination.AbsoluteUri, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { // Extracts OData-Version value from ResponseHttpHeaders. string oDataVersion = context.ResponseHttpHeaders.GetHeaderValue(Constants.ODataVersion).TrimEnd(';'); if (!string.IsNullOrEmpty(oDataVersion)) { float version = float.Parse(oDataVersion); // The minimal OData version of conformance validation is 4.0. if (version >= 4.0) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format(@"The OData version is {0} which should be not less than minimal version 4.0.", version); } } else { passed = false; detail.ErrorMessage = @"Can not get the OData-Version header from response headers."; } } else { passed = null; detail.ErrorMessage = "Cannot get response from above URI."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; VerificationHelper.VerifySearch(context, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } return passed; }
/// <summary> /// Substitudes macros in xslt instructions with corresponding property values of the current interop request context /// </summary> /// <param name="context">The interop request context</param> /// <param name="xslt">xslt instructions</param> /// <returns>xslt instructions with all the macroes substituded</returns> public static string Preprocess(ServiceContext context, string xslt) { if (context == null) { throw new ArgumentNullException("context"); } if (string.IsNullOrEmpty(xslt)) { throw new ArgumentException(Resource.ArgumentNotNullOrEmpty, "xslt"); } return xslt.Replace("$ENTITYTYPE$", context.EntityTypeShortName) .Replace("$NSENTITYTYPE$", context.EntityTypeFullName) .Replace("$URI$", context.DestinationBasePath) .Replace("$LSURI$", context.DestinationBaseLastSegment); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; string url = context.Destination.AbsoluteUri.TrimEnd('/') + @"/$metadata"; var response = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(string.Empty, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { // Get EntityContainer from metadata payload. string xpath = @"//*[local-name()='EntityContainer']"; XElement metadata = XElement.Parse(response.ResponsePayload); IEnumerable<XElement> entityContainer = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance); List<string> propNames = new List<string>(); foreach (var prop in entityContainer) { propNames.Add(prop.Attribute("Name").Value); } if (propNames.Count > 0) { passed = true; } else { passed = false; detail.ErrorMessage = "There is no EntityContainer in metadata document."; } } else { passed = false; detail.ErrorMessage = String.Format("No response returned from above URI."); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool svcDocResult = false; bool metadataResult = false; bool errorResponseResult = false; bool feedAndEntryResult = false; ExtensionRuleViolationInfo infoForOne = null; List<ExtensionRuleResultDetail> details = new List<ExtensionRuleResultDetail>(); svcDocResult = VerificationHelper.VerifySvcDoc(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } metadataResult = VerificationHelper.VerifyMetadata(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } errorResponseResult = VerificationHelper.VerifyError(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } feedAndEntryResult = VerificationHelper.VerifyFeedAndEntry(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); info.SetDetailsName(this.Name); return svcDocResult && metadataResult && feedAndEntryResult && errorResponseResult; }
/// <summary> /// Verifies the specified interop request context with the rule /// </summary> /// <param name="context">The interop request context</param> /// <param name="result">Output parameter of validation result</param> /// <returns>True if passed; false if failed</returns> public bool Verify(ServiceContext context, out TestResult result) { if (context == null) { throw new ArgumentNullException("context"); } if (context.PayloadFormat != PayloadFormat.Xml && context.PayloadFormat != PayloadFormat.Atom) { throw new ArgumentException(Resource.PayloadFormatUnexpected); } if (!context.HasMetadata) { throw new ArgumentException(Resource.MetadataUnavailable); } string xsltMaterialized = XsltRulePreprocessor.Preprocess(context, this.xslt); return XsltRngVerifier.Verify(xsltMaterialized, context.ResponsePayload, context.MetadataDocument, out result); }
/// <summary> /// Verifies whether the specific interop request context pass the validation or not /// </summary> /// <param name="context">Current interop request context</param> /// <param name="result">Output parameter of TestResult object</param> /// <returns>True if passed; false if failed</returns> public bool Verify(ServiceContext context, out TestResult result) { if (context == null) { throw new ArgumentNullException("context"); } bool? flagExec; ExtensionRuleViolationInfo info; flagExec = this.semanticExtensionVerifier(context, out info); bool passed = flagExec.HasValue ? flagExec.Value : true; result = new TestResult(); if (info != null) { result.ErrorDetail = info.Message; result.LineNumberInError = info.PayloadLineNumberInError; if (info.Endpoint != null) { result.TextInvolved = info.Endpoint.AbsoluteUri; } if (info.Details != null) { result.Details = new List<ExtensionRuleResultDetail>(); foreach (ExtensionRuleResultDetail detail in info.Details) { result.Details.Add(detail.Clone()); } } } if (!flagExec.HasValue) { result.Classification = Constants.ClassificationNotApplicable; } return passed; }
/// <summary> /// Executes one rule to validate the current interop request contecxt /// </summary> /// <param name="context">the current interop request context</param> /// <param name="rule">the rule to be validated</param> /// <returns>TestResult object of the validation</returns> /// <exception cref="Exception">Throws various exception when rule engine encounters unrecoverable errors like bad dynamic rules</exception> public static TestResult ExecuteRule(ServiceContext context, Rule rule) { if (context == null) { throw new ArgumentNullException("context"); } if (rule == null) { throw new ArgumentNullException("rule"); } bool passed = true; TestResult result; TestResult dummy; //Set the test service's current verified rule if (DataService.serviceInstance != null) { DataService.serviceInstance.SwitchRule(rule.Name); } if (rule.Condition == null || rule.Condition.Verify(context, out dummy)) { passed = rule.Action.Verify(context, out result); } else { result = new TestResult(); } result.JobId = context.JobId; result.SetProperties(rule, passed); return result; }
/// <summary> /// Gets web response of Uri request with custom header DataServiceVersion /// </summary> /// <param name="uri">Uri of request</param> /// <param name="inJsonFormat">Flag of whether response in Json format is expected</param> /// <param name="headers">Headers sent in web request</param> /// <param name="maximumPayloadSize">Maximum size of response payload in byte to be received</param> /// <param name="ctx">The reference context whose request headers are carried over</param> /// <returns>Web response</returns> public static Response GetWithHeaders(Uri uri, bool inJsonFormat, IEnumerable<KeyValuePair<string, string>> headers, int maximumPayloadSize, ServiceContext context) { var req = WebRequest.Create(uri); var reqHttp = req as HttpWebRequest; if (context.RequestHeaders != null) { foreach (var head in context.RequestHeaders) { reqHttp.Headers[head.Key] = head.Value; } } if (headers != null) { foreach (var head in headers) { reqHttp.Headers[head.Key] = head.Value; } } string acceptHeaderValue = inJsonFormat ? Constants.AcceptHeaderJson : Constants.AcceptHeaderAtom; return WebResponseHelper.Get(reqHttp, acceptHeaderValue, maximumPayloadSize); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; string url = string.Format("{0}/?$find=*", context.Destination); var req = WebRequest.Create(url) as HttpWebRequest; Response response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name, url, "GET", string.Empty, response); if (response != null && response.StatusCode != null) { if (response.StatusCode != HttpStatusCode.OK) { passed = true; } else { passed = false; detail1.ErrorMessage = "Services SHOULD fail the above URI because it contains query options 'find' which services does not understand."; } } else { passed = false; detail1.ErrorMessage = "No response returned from above URI."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return passed; }
/// <summary> /// Verify Metadata.Core.4265 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out parameter to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; var metadata = XElement.Parse(context.MetadataDocument); string xPath = "//*[local-name()='Function']"; var functionElems = metadata.XPathSelectElements(xPath, ODataNamespaceManager.Instance); if (null != functionElems && functionElems.Any()) { foreach (var functionElem in functionElems) { if (null != functionElem.Attribute("Name")) { string nameAttribVal = functionElem.GetAttributeValue("Name"); if (nameAttribVal.IsSimpleIdentifier()) { passed = true; } else { passed = false; break; } } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); var detail1 = new ExtensionRuleResultDetail(this.Name); var detail2 = new ExtensionRuleResultDetail(this.Name); var detail3 = new ExtensionRuleResultDetail(this.Name); var detail4 = new ExtensionRuleResultDetail(this.Name); var detail5 = new ExtensionRuleResultDetail(this.Name); var detail6 = new ExtensionRuleResultDetail(this.Name); var entityType = MetadataHelper.GetConcurrencyEntityType(serviceStatus.MetadataDocument); if (null == entityType) { detail1.ErrorMessage = "Cannot find an entity which contains a concurrency property in the service."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } var normalPropNames = entityType.NormalProperties.Where(np => "Edm.String" == np.PropertyType && !np.IsKey).Select(np => np.PropertyName); if (normalPropNames.Any()) { string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { var entityId = additionalInfos.Last().EntityId; var hasEtag = additionalInfos.Last().HasEtag; if (!hasEtag) { detail1.ErrorMessage = "The new inserted entity does not contain an @odata.etag annotation."; info = new ExtensionRuleViolationInfo(new Uri(entityId), resp.ResponsePayload, detail2); return passed; } resp = WebHelper.GetEntity(entityId, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, StringHelper.MergeHeaders(string.Empty, serviceStatus.DefaultHeaders), resp); if (HttpStatusCode.OK == resp.StatusCode) { reqDataStr = dFactory.ConstructUpdatedEntityData(reqData, normalPropNames).ToString(); var header = new KeyValuePair<string, string>("If-Match", additionalInfos.Last().ODataEtag); var headers = new List<KeyValuePair<string, string>>() { header }; resp = WebHelper.UpdateEntity(entityId, reqDataStr, HttpMethod.Patch, headers); detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Patch, StringHelper.MergeHeaders(string.Empty, headers), resp, string.Empty, reqDataStr); if (HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.GetEntity(entityId, serviceStatus.DefaultHeaders); detail4 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, StringHelper.MergeHeaders(string.Empty, serviceStatus.DefaultHeaders), resp); if (HttpStatusCode.OK == resp.StatusCode) { resp = WebHelper.DeleteEntity(entityId, hasEtag); detail5 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Delete, StringHelper.MergeHeaders(string.Empty, new List<KeyValuePair<string, string>>() { header }), resp); if (HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.GetEntity(entityId); detail6 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, string.Empty, resp); if (HttpStatusCode.NotFound == resp.StatusCode) { passed = true; } else { passed = false; detail6.ErrorMessage = "It still can get the deleted entity from above URI."; } } else { passed = false; detail5.ErrorMessage = "Delete entity failed."; } } else { passed = false; detail4.ErrorMessage = "Can not get the created entity from above URI."; } } else { passed = false; detail3.ErrorMessage = "Update entity failed."; } } } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI."; } } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2, detail3, detail4, detail5, detail6 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name); ExtensionRuleResultDetail detail2 = new ExtensionRuleResultDetail(this.Name); List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count()) { detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } // To get test entity which is deleteable and insertable EntityTypeElement entityType = null; foreach (var entityEle in entityTypeElements) { var matchEntity = entityEle.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetInsertRestrictions, AnnotationsHelper.GetDeleteRestrictions }); if (!string.IsNullOrEmpty(matchEntity.Item1) && matchEntity.Item2 != null && matchEntity.Item2.Any() && matchEntity.Item3 != null && matchEntity.Item3.Any()) { entityType = entityEle; break; } } if (null == entityType) { detail1.ErrorMessage = "To verify this rule it expects an entity type with deleteable and insertable restrictions, but there is no entity type in metadata which is insertable and deleteable."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); if (string.IsNullOrEmpty(entitySetUrl)) { detail1.ErrorMessage = string.Format("Cannot find the entity-set URL which is matched with {0}.", entityType.EntityTypeShortName); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); // If create successfully, the resource is updatable and deletable. if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.Created) { // Get feed response. resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp); if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.OK) { JObject jo; resp.ResponsePayload.TryToJObject(out jo); var entries = JsonParserHelper.GetEntries(jo); foreach (JObject entry in entries) { if (entry[Constants.V4OdataEditLink] == null) { passed = false; detail2.ErrorMessage = "Not all entities from above URI contain edit links."; break; } } if (passed == null) { passed = true; } } else { passed = false; detail2.ErrorMessage = "Get feed resource failed from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(additionalInfos); } else { passed = null; detail1.ErrorMessage = "Created new entity failed, it is not an updatable resource and can not verify this rule."; } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verify Entry.Core.4634 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out paramater to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; const string relAttribPrefixName = @"http://docs.oasis-open.org/odata/ns/related/"; string xpath = string.Format(@"//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='NavigationProperty']", context.EntityTypeShortName); XElement metadata = XElement.Parse(context.MetadataDocument); var navigProps = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance); List<string> relURLFullNames = new List<string>(); foreach (var np in navigProps) { relURLFullNames.Add(relAttribPrefixName + np.Attribute(@"Name").Value); } xpath = @"/atom:entry/atom:link[@type='application/atom+xml;type=entry' or @type='application/atom+xml;type=feed']"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList linkElements = xmlDoc.SelectNodes(xpath, ODataNamespaceManager.Instance); foreach (XmlNode le in linkElements) { if (relURLFullNames.Contains(le.Attributes["rel"].Value) && Uri.IsWellFormedUriString(le.Attributes["rel"].Value, UriKind.Absolute)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } return passed; }