/// <summary> /// Visits the children of the given payload element and replaces it with a copy if any child changes /// </summary> /// <param name="payloadElement">The payload element to potentially replace</param> /// <returns>The original element or a copy to replace it with</returns> public virtual ODataPayloadElement Visit(ODataErrorPayload payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); var innerError = payloadElement.InnerError; if (innerError != null) { // Note: we specifically allow it to be replaced with null innerError = this.Recurse(innerError) as ODataInternalExceptionPayload; } if (this.ShouldReplace(payloadElement.InnerError, innerError)) { return(payloadElement.ReplaceWith( new ODataErrorPayload() { Message = payloadElement.Message, Code = payloadElement.Code, InnerError = innerError, })); } return(payloadElement); }
/// <summary> /// Compares the ClientExpectedException to the provided exception and verifies the exception is correct /// </summary> /// <param name="expectedClientException">Expected Client Exception</param> /// <param name="exception">Actual Exception</param> public void Compare(ExpectedClientErrorBaseline expectedClientException, Exception exception) { ExceptionUtilities.CheckAllRequiredDependencies(this); if (expectedClientException == null) { string exceptionMessage = null; if (exception != null) { exceptionMessage = exception.ToString(); } this.Assert.IsNull(exception, "Expected to not recieve an exception:" + exceptionMessage); return; } this.Assert.IsNotNull(exception, "Expected Exception to not be null"); this.Assert.AreEqual(expectedClientException.ExpectedExceptionType, exception.GetType(), string.Format(CultureInfo.InvariantCulture, "ExceptionType is not equal, receieved the following exception: {0}", exception.ToString())); if (expectedClientException.HasServerSpecificExpectedMessage) { if (this.ShouldVerifyServerMessageInClientException) { this.Assert.IsNotNull(exception.InnerException, "Expected Inner Exception to contain ODataError"); byte[] byteArrPayload = HttpUtilities.DefaultEncoding.GetBytes(exception.InnerException.Message); ODataErrorPayload errorPayload = this.ProtocolFormatStrategySelector.DeserializeAndCast <ODataErrorPayload>(null, MimeTypes.ApplicationXml, byteArrPayload); expectedClientException.ExpectedExceptionMessage.VerifyMatch(this.systemDataServicesVerifier, errorPayload.Message, true); } } else { expectedClientException.ExpectedExceptionMessage.VerifyMatch(this.systemDataServicesClientVerifier, exception.Message, true); } }
/// <summary> /// Visits the payload element /// </summary> /// <param name="payloadElement">The payload element to visit</param> public override void Visit(ODataErrorPayload payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); ExceptionUtilities.CheckObjectNotNull(this.currentXElement, "Current XElement is not defined"); XElement errorElement = CreateMetadataElement(this.currentXElement, ODataConstants.ErrorElementName); string code = payloadElement.Code; if (code != null) { XElement codeElement = CreateMetadataElement(errorElement, ODataConstants.CodeElementName); codeElement.Add(code); } string message = payloadElement.Message; if (message != null) { XElement messageElement = CreateMetadataElement(errorElement, ODataConstants.MessageElementName); messageElement.Add(message); } ODataInternalExceptionPayload innerError = payloadElement.InnerError; if (innerError != null) { XElement innerErrorElement = CreateMetadataElement(errorElement, ODataConstants.InnerErrorElementName); this.VisitPayloadElement(innerError, innerErrorElement); } PostProcessXElement(payloadElement, errorElement); }
/// <summary> /// Visits a payload element whose root is an ODataErrorPayload. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public virtual void Visit(ODataErrorPayload payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); if (payloadElement.InnerError != null) { this.Recurse(payloadElement.InnerError); } }
public override void Visit(ODataErrorPayload payloadElement) { ExceptionUtilities.Assert(this.items.Count == 0, "Error should only be top level"); var error = new ODataError() { ErrorCode = payloadElement.Code, Message = payloadElement.Message }; this.items.Push(error); base.Visit(payloadElement); }
/// <summary> /// Converts an <see cref="ODataErrorpayload"/> into the corresponding <see cref="ODataError"/>. /// </summary> /// <param name="errorPayload">The error payload to convert.</param> /// <param name="forAtom">true if the conversion follows ATOM format rules; false for JSON format rules.</param> /// <returns>A new <see cref="ODataError"/> representing the <paramref name="errorPayload"/>.</returns> private static ODataError ConvertErrorPayload(ODataErrorPayload errorPayload, bool forAtom) { ODataError error = new ODataError(); error.ErrorCode = errorPayload.Code; error.Message = errorPayload.Message;; ODataInternalExceptionPayload innerErrorPayload = errorPayload.InnerError; if (innerErrorPayload != null) { error.InnerError = ConvertInnerErrorPayload(innerErrorPayload); } return(error); }
/// <summary> /// Helper method for getting the error payload from the response. Handles a special case for media-resource operations which may contain errors despite not normally /// being deserialized as such. /// </summary> /// <param name="response">The current response</param> /// <param name="formatSelector">The format selector to use if the response needs to be deserialized</param> /// <param name="errorPayload">The error payload if one was found</param> /// <returns>Whether or not an error payload was found</returns> internal static bool TryGetErrorPayloadFromResponse(ODataResponse response, IProtocolFormatStrategySelector formatSelector, out ODataErrorPayload errorPayload) { ExceptionUtilities.CheckArgumentNotNull(response, "response"); errorPayload = null; var payload = response.RootElement; if (payload == null) { return false; } if (payload.ElementType == ODataPayloadElementType.ODataErrorPayload) { errorPayload = (ODataErrorPayload)payload; return true; } // From here out, try to handle special case for streams which come back with error payloads and are not interpreted if (payload.ElementType != ODataPayloadElementType.PrimitiveValue) { return false; } var body = ((PrimitiveValue)payload).ClrValue as byte[]; if (body == null) { return false; } var contentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType); if (contentType == null) { return false; } // deserialize it ExceptionUtilities.CheckArgumentNotNull(formatSelector, "formatSelector"); var formatForContentType = formatSelector.GetStrategy(contentType, null); var deserializer = formatForContentType.GetDeserializer(); payload = deserializer.DeserializeFromBinary(body, new ODataPayloadContext { EncodingName = HttpUtilities.GetContentTypeCharsetOrNull(contentType) }); errorPayload = payload as ODataErrorPayload; return errorPayload != null; }
/// <summary> /// Verifies the ExceptionMessage recursively /// </summary> /// <param name="expectedErrorMessage">Error Message to Verify</param> /// <param name="resourceVerifier">Resource Verifier to use</param> /// <param name="errorPayload">Error payload to verify</param> /// <param name="assert">assert call to make</param> public static void VerifyExceptionMessage(this ExpectedErrorMessage expectedErrorMessage, IStringResourceVerifier resourceVerifier, ODataErrorPayload errorPayload, Action<bool, string> assert) { ExceptionUtilities.CheckArgumentNotNull(expectedErrorMessage, "expectedErrorMessage"); ExceptionUtilities.CheckArgumentNotNull(resourceVerifier, "resourceVerifier"); ExceptionUtilities.CheckArgumentNotNull(errorPayload, "errorPayload"); ExceptionUtilities.CheckArgumentNotNull(assert, "assert"); // Verify messages are the same // TODO: Need to also verify the language and code expectedErrorMessage.VerifyMatch(resourceVerifier, errorPayload.Message, true); ExpectedErrorMessage expectedInnerError = expectedErrorMessage.InnerError; ODataInternalExceptionPayload innerError = errorPayload.InnerError; // Set it to null so comparison won't occur if (expectedErrorMessage.SkipInnerErrorVerification) { innerError = null; expectedInnerError = null; } while (innerError != null) { // TODO: better error message assert(expectedInnerError != null, "Did not expect inner error"); // Verify messages are the same expectedInnerError.VerifyMatch(resourceVerifier, innerError.Message, true); if (expectedInnerError.SkipInnerErrorVerification) { innerError = null; expectedInnerError = null; } else { // TODO: verify stack trace, type name, etc innerError = innerError.InternalException; expectedInnerError = expectedInnerError.InnerError; } } }
/// <summary> /// Visits a payload element whose root is an ODataErrorPayload. /// </summary> /// <param name="expected">The root node of payload element being visited.</param> public void Visit(ODataErrorPayload expected) { ExceptionUtilities.CheckArgumentNotNull(expected, "expected"); var observed = this.GetNextObservedElement <ODataErrorPayload>(); using (this.Assert.WithMessage("Error did not match expectation")) { this.Assert.AreEqual(expected.Message, observed.Message, "Message did not match expectation"); this.Assert.AreEqual(expected.Code, observed.Code, "Code did not match expectation"); this.CompareAnnotations(expected.Annotations, observed.Annotations); if (expected.InnerError != null) { this.Assert.IsNotNull(observed.InnerError, "Inner error unexpectedly null"); this.WrapAccept(expected.InnerError, observed.InnerError); } else { this.Assert.IsNull(observed.InnerError, "Inner error unexpectedly non-null"); } } }
/// <summary> /// Visits a payload element whose root is an ODataErrorPayload. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(ODataErrorPayload payloadElement) { throw new TaupoNotSupportedException("Not supported yet"); }
/// <summary> /// Parse the error tag from an Odata response. It is assumed that the error portion is well formed xml. /// </summary> /// <param name="reader">Reader where the start error tag has already been parsed.</param> /// <returns>The resulting error payload.</returns> public ODataErrorPayload ParseErrorFragment(XmlReader reader) { // example xml error fragment // <m:error> // <m:code>…</> // <m:message xml:lang=”…”>…</> // <m:innererror> // <m:message>…</> // <m:type>…</> // <m:stacktrace>…</> // <m:internalexception> // … another inner error structure … // </> // </m:innererror> // </m:error> ODataErrorPayload topLevelError = new ODataErrorPayload(); ODataInternalExceptionPayload innerError = null; int errorStartDepth = reader.Depth; while (reader.Read()) { if (reader.IsStartElement() && reader.NamespaceURI == ODataConstants.DataServicesMetadataNamespaceName) { if (reader.LocalName == ODataConstants.InnerErrorElementName) { this.Assert.IsNull(innerError, "Should not find inner error element on internal exceptions"); topLevelError.InnerError = innerError = new ODataInternalExceptionPayload(); } else if (reader.LocalName == ODataConstants.InternalExceptionElementName) { this.Assert.IsNotNull(innerError, "Should not find internal exception element on top-level errors"); ExceptionUtilities.Assert(innerError.InternalException == null, "Expected internal error to be null"); innerError.InternalException = new ODataInternalExceptionPayload(); innerError = innerError.InternalException; } else if (reader.LocalName == ODataConstants.MessageElementName) { if (reader.HasAttributes) { this.Assert.IsNull(innerError, "Should not find attributes on inner errors"); } if (!reader.IsEmptyElement) { reader.Read(); if (innerError == null) { topLevelError.Message = reader.Value; } else { innerError.Message = reader.Value; } } } else if (reader.LocalName == ODataConstants.CodeElementName) { this.Assert.IsNull(innerError, "Should not find code element on inner errors"); if (!reader.IsEmptyElement) { reader.Read(); topLevelError.Code = reader.Value; } } else if (reader.LocalName == ODataConstants.TypeNameElementName) { this.Assert.IsNotNull(innerError, "Should not find type name element on top-level errors"); if (!reader.IsEmptyElement) { reader.Read(); innerError.TypeName = reader.Value; } } else if (reader.LocalName == ODataConstants.StackTraceElementName) { this.Assert.IsNotNull(innerError, "Should not find stack trace element on top-level errors"); if (!reader.IsEmptyElement) { reader.Read(); innerError.StackTrace = reader.Value; } } } // don't read past the end of <error> since there may be un-closed tags if (reader.Depth == errorStartDepth) { break; } } return topLevelError; }
/// <summary> /// Creates several PayloadTestDescriptors containing Batch Responses /// </summary> /// <param name="requestManager">Used for building the requests/responses.</param> /// <param name="model">The model to use for adding additional types.</param> /// <param name="withTypeNames">Whether or not to use full type names.</param> /// <returns>PayloadTestDescriptors</returns> public static IEnumerable <PayloadTestDescriptor> CreateBatchResponseTestDescriptors( IODataRequestManager requestManager, EdmModel model, bool withTypeNames = false) { EdmEntityType personType = null; EdmComplexType carType = null; if (model != null) { //TODO: CLONE for EdmModel //model = model.Clone(); personType = model.FindDeclaredType("TestModel.TFPerson") as EdmEntityType; carType = model.FindDeclaredType("TestModel.TFCar") as EdmComplexType; // Create the metadata types for the entity instance used in the entity set if (carType == null) { carType = new EdmComplexType("TestModel", "TFCar"); model.AddElement(carType); carType.AddStructuralProperty("Make", EdmPrimitiveTypeKind.String, true); carType.AddStructuralProperty("Color", EdmPrimitiveTypeKind.String, true); } if (personType == null) { personType = new EdmEntityType("TestModel", "TFPerson"); model.AddElement(personType); personType.AddKeys(personType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); personType.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String, true); personType.AddStructuralProperty("Car", carType.ToTypeReference()); EdmEntityContainer container = (EdmEntityContainer)model.EntityContainer; if (container == null) { container = new EdmEntityContainer("TestModel", "DefaultContainer"); model.AddElement(container); container.AddEntitySet("Customers", personType); container.AddEntitySet("TFPerson", personType); } } } ComplexInstance carInstance = PayloadBuilder.ComplexValue(withTypeNames ? "TestModel.TFCar" : null) .Property("Make", PayloadBuilder.PrimitiveValue("Ford")) .Property("Color", PayloadBuilder.PrimitiveValue("Blue")); ComplexProperty carProperty = (ComplexProperty)PayloadBuilder.Property("Car", carInstance) .WithTypeAnnotation(carType); EntityInstance personInstance = PayloadBuilder.Entity(withTypeNames ? "TestModel.TFPerson" : null) .Property("Id", PayloadBuilder.PrimitiveValue(1)) .Property("Name", PayloadBuilder.PrimitiveValue("John Doe")) .Property("Car", carInstance) .WithTypeAnnotation(personType); ODataErrorPayload errorInstance = PayloadBuilder.Error("ErrorCode") .Message("ErrorValue") .InnerError( PayloadBuilder.InnerError().Message("InnerErrorMessage").StackTrace("InnerErrorStackTrace").TypeName("InnerErrorTypeName")); var carPropertyPayload = new PayloadTestDescriptor() { PayloadElement = carProperty, PayloadEdmModel = model }; var emptyPayload = new PayloadTestDescriptor() { PayloadEdmModel = CreateEmptyEdmModel() }; var personPayload = new PayloadTestDescriptor() { // This payload will be serialised to JSON so we need the annotation to mark it as a response. PayloadElement = personInstance.AddAnnotation(new PayloadFormatVersionAnnotation() { Response = true, ResponseWrapper = true }), PayloadEdmModel = model }; var errorPayload = new PayloadTestDescriptor() { PayloadElement = errorInstance, PayloadEdmModel = model, }; // response operation with a status code of 5 containing a complex instance var carPropertyPayloadOperation = carPropertyPayload.InResponseOperation(5, requestManager); // response operation with no payload and a status code of 200 var emptyPayloadOperation = emptyPayload.InResponseOperation(200, requestManager); // response operation with a status code of 418 containing an entity instance var personPayloadOperation = personPayload.InResponseOperation(418, requestManager, MimeTypes.ApplicationJsonLight); // response operation with a status code of 404 containing an error instance var errorPayloadOperation = errorPayload.InResponseOperation(404, requestManager); // changeset with multiple operations var twoOperationsChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { carPropertyPayloadOperation, emptyPayloadOperation }, requestManager); // changesets with a single operation var oneOperationChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { personPayloadOperation }, requestManager); var oneErrorChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { errorPayloadOperation }, requestManager); // empty changeset var emptyChangeset = BatchUtils.GetResponseChangeset(new IMimePart[] { }, requestManager); // Empty Batch yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { }) .AddAnnotation(new BatchBoundaryAnnotation("bb_emptybatch")), PayloadEdmModel = emptyPayload.PayloadEdmModel, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Single Operation yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { carPropertyPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_singleoperation")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Multiple Operations yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { carPropertyPayloadOperation, emptyPayloadOperation, errorPayloadOperation, personPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_multipleoperations")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Single Changeset yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { twoOperationsChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_singlechangeset")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Multiple Changesets yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { twoOperationsChangeset, oneOperationChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_multiplechangesets")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); // Operations and changesets yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { twoOperationsChangeset, carPropertyPayloadOperation, oneOperationChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_1")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { carPropertyPayloadOperation, oneOperationChangeset, emptyPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_2")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload(new IMimePart[] { errorPayloadOperation, carPropertyPayloadOperation, emptyPayloadOperation, twoOperationsChangeset, oneOperationChangeset }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_3")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.BatchResponsePayload( new IMimePart[] { oneErrorChangeset, carPropertyPayloadOperation, emptyChangeset, emptyPayloadOperation, twoOperationsChangeset, personPayloadOperation, oneOperationChangeset, errorPayloadOperation }) .AddAnnotation(new BatchBoundaryAnnotation("bb_operationsandchangesets_4")), PayloadEdmModel = model, SkipTestConfiguration = (tc) => tc.IsRequest, }); }
/// <summary> /// Parse the error tag from an Odata response. It is assumed that the error portion is well formed xml. /// </summary> /// <param name="reader">Reader where the start error tag has already been parsed.</param> /// <returns>The resulting error payload.</returns> public ODataErrorPayload ParseErrorFragment(XmlReader reader) { // example xml error fragment // <m:error> // <m:code>…</> // <m:message xml:lang=”…”>…</> // <m:innererror> // <m:message>…</> // <m:type>…</> // <m:stacktrace>…</> // <m:internalexception> // … another inner error structure … // </> // </m:innererror> // </m:error> ODataErrorPayload topLevelError = new ODataErrorPayload(); ODataInternalExceptionPayload innerError = null; int errorStartDepth = reader.Depth; while (reader.Read()) { if (reader.IsStartElement() && reader.NamespaceURI == ODataConstants.DataServicesMetadataNamespaceName) { if (reader.LocalName == ODataConstants.InnerErrorElementName) { this.Assert.IsNull(innerError, "Should not find inner error element on internal exceptions"); topLevelError.InnerError = innerError = new ODataInternalExceptionPayload(); } else if (reader.LocalName == ODataConstants.InternalExceptionElementName) { this.Assert.IsNotNull(innerError, "Should not find internal exception element on top-level errors"); ExceptionUtilities.Assert(innerError.InternalException == null, "Expected internal error to be null"); innerError.InternalException = new ODataInternalExceptionPayload(); innerError = innerError.InternalException; } else if (reader.LocalName == ODataConstants.MessageElementName) { if (reader.HasAttributes) { this.Assert.IsNull(innerError, "Should not find attributes on inner errors"); } if (!reader.IsEmptyElement) { reader.Read(); if (innerError == null) { topLevelError.Message = reader.Value; } else { innerError.Message = reader.Value; } } } else if (reader.LocalName == ODataConstants.CodeElementName) { this.Assert.IsNull(innerError, "Should not find code element on inner errors"); if (!reader.IsEmptyElement) { reader.Read(); topLevelError.Code = reader.Value; } } else if (reader.LocalName == ODataConstants.TypeNameElementName) { this.Assert.IsNotNull(innerError, "Should not find type name element on top-level errors"); if (!reader.IsEmptyElement) { reader.Read(); innerError.TypeName = reader.Value; } } else if (reader.LocalName == ODataConstants.StackTraceElementName) { this.Assert.IsNotNull(innerError, "Should not find stack trace element on top-level errors"); if (!reader.IsEmptyElement) { reader.Read(); innerError.StackTrace = reader.Value; } } } // don't read past the end of <error> since there may be un-closed tags if (reader.Depth == errorStartDepth) { break; } } return(topLevelError); }
/// <summary> /// Helper method for getting the error payload from the response. Handles a special case for media-resource operations which may contain errors despite not normally /// being deserialized as such. /// </summary> /// <param name="response">The current response</param> /// <param name="formatSelector">The format selector to use if the response needs to be deserialized</param> /// <param name="errorPayload">The error payload if one was found</param> /// <returns>Whether or not an error payload was found</returns> internal static bool TryGetErrorPayloadFromResponse(ODataResponse response, IProtocolFormatStrategySelector formatSelector, out ODataErrorPayload errorPayload) { ExceptionUtilities.CheckArgumentNotNull(response, "response"); errorPayload = null; var payload = response.RootElement; if (payload == null) { return(false); } if (payload.ElementType == ODataPayloadElementType.ODataErrorPayload) { errorPayload = (ODataErrorPayload)payload; return(true); } // From here out, try to handle special case for streams which come back with error payloads and are not interpreted if (payload.ElementType != ODataPayloadElementType.PrimitiveValue) { return(false); } var body = ((PrimitiveValue)payload).ClrValue as byte[]; if (body == null) { return(false); } var contentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType); if (contentType == null) { return(false); } // deserialize it ExceptionUtilities.CheckArgumentNotNull(formatSelector, "formatSelector"); var formatForContentType = formatSelector.GetStrategy(contentType, null); var deserializer = formatForContentType.GetDeserializer(); payload = deserializer.DeserializeFromBinary(body, new ODataPayloadContext { EncodingName = HttpUtilities.GetContentTypeCharsetOrNull(contentType) }); errorPayload = payload as ODataErrorPayload; return(errorPayload != null); }
/// <summary> /// Visits a payload element whose root is an ODataErrorPayload. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public void Visit(ODataErrorPayload payloadElement) { throw new AssertionFailedException("Payload should not have contained an error"); }
/// <summary> /// Deserializes given HTTP payload as a json error payload or returns false /// </summary> /// <param name="serialized">The payload that was sent over HTTP</param> /// <param name="encodingName">Optional name of an encoding to use if it is relevant to the current format. May be null if no character-set information was known.</param> /// <param name="errorPayload">Error payload that is found</param> /// <returns>True if it finds and error, false if not</returns> public bool TryDeserializeErrorPayload(byte[] serialized, string encodingName, out ODataPayloadElement errorPayload) { ExceptionUtilities.CheckArgumentNotNull(serialized, "serialized"); errorPayload = null; Encoding encoding = HttpUtilities.GetEncodingOrDefault(encodingName); string payload = encoding.GetString(serialized, 0, serialized.Length); // sample json error // { // “error”: { // “code”: <string> // “message”: { // “lang”: <string>, // “value“: <string> // }, // “innererror”: { // “message”: <string>, // “type”: <string>, // “stacktrace”: <string>, // “internalexception”: { // … another inner error structure … // } // } // } // } string errorName = "\"" + ODataConstants.ErrorElementName + "\":"; int errorElementPos = payload.IndexOf(errorName, StringComparison.Ordinal); // Look in the payload and see if an error exists if (errorElementPos > -1) { ODataErrorPayload topLevelError = new ODataErrorPayload(); errorPayload = topLevelError; ODataInternalExceptionPayload innerError = null; bool inTopLevelMessage = false; bool inError = false; using (StringReader reader = new StringReader(payload.Substring(errorElementPos))) { JsonTokenizer tokenizer = new JsonTokenizer(reader); while (tokenizer.HasMoreTokens()) { if (tokenizer.TokenType == JsonTokenType.String) { string tokenValue = null; if (tokenizer != null) { tokenValue = tokenizer.Value.ToString(); } // don't start processing other properties until we're definitely inside the error itself if (!inError) { inError = tokenValue == ODataConstants.ErrorElementName; } else { if (tokenValue == ODataConstants.InnerErrorElementName) { this.Assert.IsNull(innerError, "Should not find 'innererror' property on inner errors"); topLevelError.InnerError = innerError = new ODataInternalExceptionPayload(); } else if (tokenValue == ODataConstants.InternalExceptionElementName) { this.Assert.IsNotNull(innerError, "Should not find 'internalexception' property on top-level errors"); ExceptionUtilities.Assert(innerError.InternalException == null, "Inner error should have been null"); innerError.InternalException = new ODataInternalExceptionPayload(); innerError = innerError.InternalException; } else if (tokenValue == ODataConstants.MessageElementName) { if (innerError == null) { inTopLevelMessage = true; } else { innerError.Message = this.GetIdentifierValue(tokenizer); } } else if (tokenValue == ODataConstants.ValueElementName) { this.Assert.IsTrue(inTopLevelMessage, "Should not find 'value' property outside top-level message"); this.Assert.IsNull(innerError, "Should not find 'value' property on inner errors"); topLevelError.Message = this.GetIdentifierValue(tokenizer); } else if (tokenValue == ODataConstants.CodeElementName) { this.Assert.IsNull(innerError, "Should not find 'code' property on inner errors"); topLevelError.Code = this.GetIdentifierValue(tokenizer); } else if (tokenValue == ODataConstants.TypeNameElementName) { this.Assert.IsNotNull(innerError, "Should not find 'type' on top-level errors"); innerError.TypeName = this.GetIdentifierValue(tokenizer); } else if (tokenValue == ODataConstants.StackTraceElementName) { this.Assert.IsNotNull(innerError, "Should not find 'stacktrace' on top-level errors"); innerError.StackTrace = this.GetIdentifierValue(tokenizer); } } } else if (tokenizer.TokenType == JsonTokenType.RightCurly) { inTopLevelMessage = false; } tokenizer.GetNextToken(); } } return true; } return false; }
/// <summary> /// Verifies the ExceptionMessage recursively /// </summary> /// <param name="expectedErrorMessage">Error Message to Verify</param> /// <param name="resourceVerifier">Resource Verifier to use</param> /// <param name="errorPayload">Error payload to verify</param> /// <param name="assert">assert call to make</param> public static void VerifyExceptionMessage(this ExpectedErrorMessage expectedErrorMessage, IStringResourceVerifier resourceVerifier, ODataErrorPayload errorPayload, Action <bool, string> assert) { ExceptionUtilities.CheckArgumentNotNull(expectedErrorMessage, "expectedErrorMessage"); ExceptionUtilities.CheckArgumentNotNull(resourceVerifier, "resourceVerifier"); ExceptionUtilities.CheckArgumentNotNull(errorPayload, "errorPayload"); ExceptionUtilities.CheckArgumentNotNull(assert, "assert"); // Verify messages are the same // TODO: Need to also verify the language and code expectedErrorMessage.VerifyMatch(resourceVerifier, errorPayload.Message, true); ExpectedErrorMessage expectedInnerError = expectedErrorMessage.InnerError; ODataInternalExceptionPayload innerError = errorPayload.InnerError; // Set it to null so comparison won't occur if (expectedErrorMessage.SkipInnerErrorVerification) { innerError = null; expectedInnerError = null; } while (innerError != null) { // TODO: better error message assert(expectedInnerError != null, "Did not expect inner error"); // Verify messages are the same expectedInnerError.VerifyMatch(resourceVerifier, innerError.Message, true); if (expectedInnerError.SkipInnerErrorVerification) { innerError = null; expectedInnerError = null; } else { // TODO: verify stack trace, type name, etc innerError = innerError.InternalException; expectedInnerError = expectedInnerError.InnerError; } } }
/// <summary> /// Deserializes given HTTP payload as a json error payload or returns false /// </summary> /// <param name="serialized">The payload that was sent over HTTP</param> /// <param name="encodingName">Optional name of an encoding to use if it is relevant to the current format. May be null if no character-set information was known.</param> /// <param name="errorPayload">Error payload that is found</param> /// <returns>True if it finds and error, false if not</returns> public bool TryDeserializeErrorPayload(byte[] serialized, string encodingName, out ODataPayloadElement errorPayload) { ExceptionUtilities.CheckArgumentNotNull(serialized, "serialized"); errorPayload = null; Encoding encoding = HttpUtilities.GetEncodingOrDefault(encodingName); string payload = encoding.GetString(serialized, 0, serialized.Length); // sample json error // { // “error”: { // “code”: <string> // “message”: { // “lang”: <string>, // “value“: <string> // }, // “innererror”: { // “message”: <string>, // “type”: <string>, // “stacktrace”: <string>, // “internalexception”: { // … another inner error structure … // } // } // } // } string errorName = "\"" + ODataConstants.ErrorElementName + "\":"; int errorElementPos = payload.IndexOf(errorName, StringComparison.Ordinal); // Look in the payload and see if an error exists if (errorElementPos > -1) { ODataErrorPayload topLevelError = new ODataErrorPayload(); errorPayload = topLevelError; ODataInternalExceptionPayload innerError = null; bool inTopLevelMessage = false; bool inError = false; using (StringReader reader = new StringReader(payload.Substring(errorElementPos))) { JsonTokenizer tokenizer = new JsonTokenizer(reader); while (tokenizer.HasMoreTokens()) { if (tokenizer.TokenType == JsonTokenType.String) { string tokenValue = null; if (tokenizer != null) { tokenValue = tokenizer.Value.ToString(); } // don't start processing other properties until we're definitely inside the error itself if (!inError) { inError = tokenValue == ODataConstants.ErrorElementName; } else { if (tokenValue == ODataConstants.InnerErrorElementName) { this.Assert.IsNull(innerError, "Should not find 'innererror' property on inner errors"); topLevelError.InnerError = innerError = new ODataInternalExceptionPayload(); } else if (tokenValue == ODataConstants.InternalExceptionElementName) { this.Assert.IsNotNull(innerError, "Should not find 'internalexception' property on top-level errors"); ExceptionUtilities.Assert(innerError.InternalException == null, "Inner error should have been null"); innerError.InternalException = new ODataInternalExceptionPayload(); innerError = innerError.InternalException; } else if (tokenValue == ODataConstants.MessageElementName) { if (innerError == null) { inTopLevelMessage = true; } else { innerError.Message = this.GetIdentifierValue(tokenizer); } } else if (tokenValue == ODataConstants.ValueElementName) { this.Assert.IsTrue(inTopLevelMessage, "Should not find 'value' property outside top-level message"); this.Assert.IsNull(innerError, "Should not find 'value' property on inner errors"); topLevelError.Message = this.GetIdentifierValue(tokenizer); } else if (tokenValue == ODataConstants.CodeElementName) { this.Assert.IsNull(innerError, "Should not find 'code' property on inner errors"); topLevelError.Code = this.GetIdentifierValue(tokenizer); } else if (tokenValue == ODataConstants.TypeNameElementName) { this.Assert.IsNotNull(innerError, "Should not find 'type' on top-level errors"); innerError.TypeName = this.GetIdentifierValue(tokenizer); } else if (tokenValue == ODataConstants.StackTraceElementName) { this.Assert.IsNotNull(innerError, "Should not find 'stacktrace' on top-level errors"); innerError.StackTrace = this.GetIdentifierValue(tokenizer); } } } else if (tokenizer.TokenType == JsonTokenType.RightCurly) { inTopLevelMessage = false; } tokenizer.GetNextToken(); } } return(true); } return(false); }
/// <summary> /// Converts an <see cref="ODataErrorpayload"/> into the corresponding <see cref="ODataError"/>. /// </summary> /// <param name="errorPayload">The error payload to convert.</param> /// <param name="forAtom">true if the conversion follows ATOM format rules; false for JSON format rules.</param> /// <returns>A new <see cref="ODataError"/> representing the <paramref name="errorPayload"/>.</returns> private static ODataError ConvertErrorPayload(ODataErrorPayload errorPayload, bool forAtom) { ODataError error = new ODataError(); error.ErrorCode = errorPayload.Code; error.Message = errorPayload.Message; ; ODataInternalExceptionPayload innerErrorPayload = errorPayload.InnerError; if (innerErrorPayload != null) { error.InnerError = ConvertInnerErrorPayload(innerErrorPayload); } return error; }
public void TopLevelAtomErrorTest() { #region Extra attributes on the error elements (and sub-elements) var extraAttributePayloads = new[] { new { PayloadElement = PayloadBuilder.Error(), Template = "<m:error {0} />", }, new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode"), Template = "<m:error><m:code {0}>ErrorCode</m:code></m:error>" }, new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode").Message("Message"), Template = "<m:error><m:code>ErrorCode</m:code><m:message {0}>Message</m:message></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError()), Template = "<m:error><m:innererror {0}></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("InnerMessage")), Template = "<m:error><m:innererror><m:message {0}>InnerMessage</m:message></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName("TypeName")), Template = "<m:error><m:innererror><m:type {0}>TypeName</m:type></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().StackTrace("StackTrace")), Template = "<m:error><m:innererror><m:stacktrace {0}>StackTrace</m:stacktrace></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(new ODataInternalExceptionPayload())), Template = "<m:error><m:innererror><m:internalexception {0}></m:internalexception></m:innererror></m:error>" }, }; string[] attributes = new string[] { "foo='bar'", "m:foo='bar'", "foo=''", "lang='invalid'", }; IEnumerable <PayloadReaderTestDescriptor> testDescriptors = extraAttributePayloads.SelectMany(extraAttributePayload => attributes.Select(attribute => { var payloadElement = extraAttributePayload.PayloadElement.DeepCopy(); string xmlRep = string.Format(CultureInfo.InvariantCulture, extraAttributePayload.Template, attribute); payloadElement = payloadElement.XmlRepresentation(xmlRep); return(new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = payloadElement }); })); #endregion Extra attributes on the error elements (and sub-elements) #region Extra padding in the error elements' content var extraPaddingPayloads = new[] { new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode"), Template = "<m:error>{0}<m:code>ErrorCode</m:code></m:error>" }, new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode"), Template = "<m:error><m:code>ErrorCode</m:code>{0}</m:error>" }, new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode").Message("Message"), Template = "<m:error><m:code>ErrorCode</m:code>{0}<m:message>Message</m:message></m:error>" }, new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode").Message("Message").InnerError(PayloadBuilder.InnerError()), Template = "<m:error><m:code>ErrorCode</m:code><m:message>Message</m:message>{0}<m:innererror></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().Code("ErrorCode").Message("Message").InnerError(PayloadBuilder.InnerError()), Template = "<m:error><m:code>ErrorCode</m:code><m:message>Message</m:message><m:innererror>{0}</m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("InnerMessage")), Template = "<m:error><m:innererror>{0}<m:message>InnerMessage</m:message></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("InnerMessage")), Template = "<m:error><m:innererror><m:message>InnerMessage</m:message>{0}</m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName("TypeName")), Template = "<m:error><m:innererror>{0}<m:type>TypeName</m:type></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName("TypeName")), Template = "<m:error><m:innererror><m:type>TypeName</m:type>{0}</m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName("TypeName").StackTrace("StackTrace")), Template = "<m:error><m:innererror><m:type>TypeName</m:type>{0}<m:stacktrace>StackTrace</m:stacktrace></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName("TypeName").StackTrace("StackTrace")), Template = "<m:error><m:innererror><m:type>TypeName</m:type><m:stacktrace>StackTrace</m:stacktrace>{0}</m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(new ODataInternalExceptionPayload())), Template = "<m:error><m:innererror>{0}<m:internalexception></m:internalexception></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(new ODataInternalExceptionPayload())), Template = "<m:error><m:innererror><m:internalexception>{0}</m:internalexception></m:innererror></m:error>" }, new { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(new ODataInternalExceptionPayload())), Template = "<m:error><m:innererror><m:internalexception></m:internalexception>{0}</m:innererror></m:error>" }, }; string[] xmlPaddingToIgnore = new string[] { string.Empty, // Nothing " \r\n\t", // Whitespace only "<!--s--> <?value?>", // Insignificant nodes "some text <![CDATA[cdata]]>", // Significant nodes to be ignored "<foo xmlns=''/>", // Element in no namespace "<c:foo xmlns:c='uri' attr='1'><c:child/>text</c:foo>", // Element in custom namespace "<m:properties/>", // Element in metadata namespace (should be ignored as well) "<entry/>", // Element in atom namespace (should also be ignored) }; IEnumerable <PayloadReaderTestDescriptor> extraPaddingTestDescriptors = extraPaddingPayloads.SelectMany(extraPaddingPayload => xmlPaddingToIgnore.Select(xmlPadding => { var payloadElement = extraPaddingPayload.PayloadElement.DeepCopy(); string xmlRep = string.Format(CultureInfo.InvariantCulture, extraPaddingPayload.Template, xmlPadding); payloadElement = payloadElement.XmlRepresentation(xmlRep); return(new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = payloadElement }); })); testDescriptors = testDescriptors.Concat(extraPaddingTestDescriptors); #endregion Extra padding in the error elements' content #region Extra elements in various interesting places of an error payload ODataErrorPayload errorPayload = PayloadBuilder.Error() .Code("ErrorCode") .Message("Message") .InnerError( PayloadBuilder.InnerError() .Message("InnerMessage") .TypeName("TypeName") .StackTrace("StackTrace") .InnerError( PayloadBuilder.InnerError() .Message("InnerInnerMessage"))); XElement xmlRepresentation = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataErrorElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataErrorCodeElementName, "ErrorCode"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataErrorMessageElementName, "Message"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorMessageElementName, "InnerMessage"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorTypeElementName, "TypeName"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorStackTraceElementName, "StackTrace"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorInnerErrorElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorMessageElementName, "InnerInnerMessage")))); XElement[] extraElements = new XElement[] { new XElement(XName.Get("foo"), "bar"), new XElement(XName.Get("foo"), new XElement(XName.Get("bar"))), new XElement(XName.Get("foo"), new XAttribute(XName.Get("bar"), "attribute-value")), new XElement(TestAtomConstants.ODataMetadataXNamespace + "foo", "bar"), new XElement(TestAtomConstants.ODataMetadataXNamespace + "foo", new XElement(TestAtomConstants.ODataMetadataXNamespace + "bar")), new XElement(XName.Get("foo"), new XAttribute(TestAtomConstants.ODataMetadataXNamespace + "bar", "attribute-value")), }; IEnumerable <PayloadReaderTestDescriptor> extraElementTestDescriptors = extraElements.SelectMany(extraElement => { return(InjectElement(extraElement, xmlRepresentation).Select(errorWithInjectedElement => new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = errorPayload.DeepCopy().XmlRepresentation(errorWithInjectedElement) } )); }); testDescriptors = testDescriptors.Concat(extraElementTestDescriptors); #endregion Extra elements in various interesting places of an error payload #region Various payload orders for an error element errorPayload = PayloadBuilder.Error() .Code("ErrorCode") .Message("Message") .InnerError( PayloadBuilder.InnerError() .Message("InnerMessage") .TypeName("TypeName") .StackTrace("StackTrace") .InnerError( PayloadBuilder.InnerError() .Message("InnerInnerMessage"))); xmlRepresentation = new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataErrorElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataErrorCodeElementName, "ErrorCode"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataErrorMessageElementName, "Message"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorMessageElementName, "InnerMessage"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorTypeElementName, "TypeName"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorStackTraceElementName, "StackTrace"), new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorInnerErrorElementName, new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.ODataInnerErrorMessageElementName, "InnerInnerMessage")))); IEnumerable <PayloadReaderTestDescriptor> payloadOrderTestDescriptors = GeneratePayloadOrders(xmlRepresentation).Select(xmlRep => new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = errorPayload.DeepCopy().XmlRepresentation(xmlRep) } ); testDescriptors = testDescriptors.Concat(payloadOrderTestDescriptors); #endregion Various payload orders for an error element this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
/// <summary> /// Visits a payload element whose root is an ODataErrorPayload. /// </summary> /// <param name="payloadElement">The root node of payload element being visited.</param> public override void Visit(ODataErrorPayload payloadElement) { base.Visit(payloadElement); }
/// <summary> /// Creates a set of interesting error values. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <returns>List of test descriptors with interesting error values as payload.</returns> public static IEnumerable<PayloadTestDescriptor> CreateErrorTestDescriptors() { // error payloads IEnumerable<ODataErrorPayload> errors = new ODataErrorPayload[] { PayloadBuilder.Error().Code("ErrorCode"), PayloadBuilder.Error().Code("ErrorCode").Message("Error message"), PayloadBuilder.Error().Code("ErrorCode").Message(string.Empty), PayloadBuilder.Error().Message("Error message"), PayloadBuilder.Error().Message(string.Empty), PayloadBuilder.Error().Message("Error message"), }; foreach (ODataErrorPayload errorPayload in errors) { yield return new PayloadTestDescriptor(){ PayloadElement = errorPayload.DeepCopy() }; } // inner error payloads IEnumerable<ODataInternalExceptionPayload> innerErrors = new ODataInternalExceptionPayload[] { PayloadBuilder.InnerError(), PayloadBuilder.InnerError().Message("Inner error message"), PayloadBuilder.InnerError().StackTrace("Stack trace"), PayloadBuilder.InnerError().TypeName("Type name"), PayloadBuilder.InnerError().Message("Inner error message").StackTrace("Stack trace").TypeName("Type name"), }; // create nested inner error payloads innerErrors = innerErrors.Concat(innerErrors.Select(inner => PayloadBuilder.InnerError().Message("Outer inner error message").StackTrace("Stack trace").TypeName("Type name").InnerError(inner.DeepCopy()))); // create a deeply nested inner error payload var deeplyNestedInnerError = PayloadBuilder.InnerError(); foreach (var innerError in innerErrors) { var copyOfInnerError = innerError.DeepCopy(); if (copyOfInnerError.InternalException == null) { copyOfInnerError.InnerError(deeplyNestedInnerError); } else { ExceptionUtilities.Assert(copyOfInnerError.InternalException.InternalException == null, "Did not expect inner error nesting beyond 2"); copyOfInnerError.InternalException.InnerError(deeplyNestedInnerError); } deeplyNestedInnerError = copyOfInnerError; } innerErrors = innerErrors.ConcatSingle(deeplyNestedInnerError); // put the inner errors into an empty error and all the other error payloads. foreach (ODataInternalExceptionPayload innerError in innerErrors) { yield return new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.Error().InnerError(innerError.DeepCopy()) }; foreach (ODataErrorPayload outerError in errors) { yield return new PayloadTestDescriptor() { PayloadElement = outerError.DeepCopy().InnerError(innerError.DeepCopy()) }; } } }
/// <summary> /// Creates a set of interesting error values. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <returns>List of test descriptors with interesting error values as payload.</returns> public static IEnumerable <PayloadTestDescriptor> CreateErrorTestDescriptors() { // error payloads IEnumerable <ODataErrorPayload> errors = new ODataErrorPayload[] { PayloadBuilder.Error().Code("ErrorCode"), PayloadBuilder.Error().Code("ErrorCode").Message("Error message"), PayloadBuilder.Error().Code("ErrorCode").Message(string.Empty), PayloadBuilder.Error().Message("Error message"), PayloadBuilder.Error().Message(string.Empty), PayloadBuilder.Error().Message("Error message"), }; foreach (ODataErrorPayload errorPayload in errors) { yield return(new PayloadTestDescriptor() { PayloadElement = errorPayload.DeepCopy() }); } // inner error payloads IEnumerable <ODataInternalExceptionPayload> innerErrors = new ODataInternalExceptionPayload[] { PayloadBuilder.InnerError(), PayloadBuilder.InnerError().Message("Inner error message"), PayloadBuilder.InnerError().StackTrace("Stack trace"), PayloadBuilder.InnerError().TypeName("Type name"), PayloadBuilder.InnerError().Message("Inner error message").StackTrace("Stack trace").TypeName("Type name"), }; // create nested inner error payloads innerErrors = innerErrors.Concat(innerErrors.Select(inner => PayloadBuilder.InnerError().Message("Outer inner error message").StackTrace("Stack trace").TypeName("Type name").InnerError(inner.DeepCopy()))); // create a deeply nested inner error payload var deeplyNestedInnerError = PayloadBuilder.InnerError(); foreach (var innerError in innerErrors) { var copyOfInnerError = innerError.DeepCopy(); if (copyOfInnerError.InternalException == null) { copyOfInnerError.InnerError(deeplyNestedInnerError); } else { ExceptionUtilities.Assert(copyOfInnerError.InternalException.InternalException == null, "Did not expect inner error nesting beyond 2"); copyOfInnerError.InternalException.InnerError(deeplyNestedInnerError); } deeplyNestedInnerError = copyOfInnerError; } innerErrors = innerErrors.ConcatSingle(deeplyNestedInnerError); // put the inner errors into an empty error and all the other error payloads. foreach (ODataInternalExceptionPayload innerError in innerErrors) { yield return(new PayloadTestDescriptor() { PayloadElement = PayloadBuilder.Error().InnerError(innerError.DeepCopy()) }); foreach (ODataErrorPayload outerError in errors) { yield return(new PayloadTestDescriptor() { PayloadElement = outerError.DeepCopy().InnerError(innerError.DeepCopy()) }); } } }