/// <summary> /// Creates error reader test descriptors with deeply nested internal exceptions. /// </summary> /// <param name="settings">The test descriptor settings to use.</param> /// <param name="depthLimit">The maximum depth limit for nested errors. Payloads with error depth over this limit should fail.</param> /// <returns>An enumerable of <see cref="PayloadReaderTestDescriptor"/> representing the deeply nested error payloads.</returns> internal static IEnumerable <PayloadReaderTestDescriptor> CreateErrorDeeplyNestedReaderTestDescriptors(PayloadReaderTestDescriptor.Settings settings, int depthLimit) { ODataInternalExceptionPayload deeplyNestedInnerError = PayloadBuilder.InnerError(); // Create 'depthLimit' levels of depth (loop 'depthLimit - 1' times since we've already constructed one inner error). for (int index = 0; index < depthLimit - 1; index++) { deeplyNestedInnerError.InnerError(deeplyNestedInnerError.DeepCopy()); } // Add one more level of depth to create an invalid payload. ODataInternalExceptionPayload tooDeeplyNestedInnerError = PayloadBuilder.InnerError().InnerError(deeplyNestedInnerError.DeepCopy()); yield return(new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(deeplyNestedInnerError), SkipTestConfiguration = tc => tc.IsRequest }); yield return(new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(tooDeeplyNestedInnerError), ExpectedException = ODataExpectedExceptions.ODataException("ValidationUtils_RecursionDepthLimitReached", Convert.ToString(depthLimit)), SkipTestConfiguration = tc => tc.IsRequest }); }
/// <summary> /// Visits an inner error. /// </summary> /// <param name="innerError">The inner error to visit.</param> protected override ODataPayloadElement VisitInnerError(ODataInnerError innerError) { if (innerError == null) { return(null); } return(PayloadBuilder.InnerError() .Message(innerError.Message) .TypeName(innerError.TypeName) .StackTrace(innerError.StackTrace) .InnerError(innerError.InnerError == null ? null : (ODataInternalExceptionPayload)this.Visit(innerError.InnerError))); }
/// <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 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, }); }
public void ElementValueTest() { // TODO: Add test cases for ATOM metadata once it's implemented // Note that we don't test EPM here which we could do as well, although if we test ATOM metadata, then EPM uses almost the same code path. var targetsForEmptyString = new ElementValueTestTarget[] { // Property value new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.PrimitiveProperty(null, value).XmlRepresentation(xmlValueCreator("<m:value>{0}</m:value>", value)) }, // Error code new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.Error().Code(value).XmlRepresentation(xmlValueCreator("<m:error><m:code>{0}</m:code></m:error>", value)) }, // Error message new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.Error().Code("code").Message(value).XmlRepresentation(xmlValueCreator("<m:error><m:code>code</m:code><m:message>{0}</m:message></m:error>", value)) }, // Inner error message new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message(value)).XmlRepresentation(xmlValueCreator("<m:error><m:innererror><m:message>{0}</m:message></m:innererror></m:error>", value)) }, // Inner error type name new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName(value)).XmlRepresentation(xmlValueCreator("<m:error><m:innererror><m:type>{0}</m:type></m:innererror></m:error>", value)) }, // Inner error stacktrace new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().StackTrace(value)).XmlRepresentation(xmlValueCreator("<m:error><m:innererror><m:stacktrace>{0}</m:stacktrace></m:innererror></m:error>", value)) }, }; var targetsForNonEmptyString = new ElementValueTestTarget[] { // Entity ID new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.Entity().Id(value).XmlRepresentation(xmlValueCreator("<entry><id>{0}</id></entry>", value)) }, // Feed ID new ElementValueTestTarget { PayloadElement = (value, xmlValueCreator) => PayloadBuilder.EntitySet().AtomId(value).XmlRepresentation(xmlValueCreator("<feed><id>{0}</id></feed>", value)) } }; var targets = SetValueForTarget( new string[] { string.Empty }, targetsForEmptyString) .Concat(SetValueForTarget( new string[] { "urn:id" }, targetsForNonEmptyString.Concat(targetsForEmptyString))); var values = new ElementValueTestValue[] { // Just a simple string with no xml:space new ElementValueTestValue { XmlValueCreator = (template, value) => string.Format(CultureInfo.InvariantCulture, template, value) }, // Comments and PIS before and after with no xml:space new ElementValueTestValue { XmlValueCreator = (template, value) => string.Format(CultureInfo.InvariantCulture, template, "<!--before-->" + value + "<!--after-->") }, // Insignificant whitespace before and after new ElementValueTestValue { XmlValueCreator = (template, value) => string.Format(CultureInfo.InvariantCulture, template, " <?before?>" + value + "<!--after-->\n\t") }, // Comments, PI and whitespace in the middle new ElementValueTestValue { XmlValueCreator = (template, value) => { if (value.Length < 2) { return(string.Format(CultureInfo.InvariantCulture, template, value)); } int splitIndex = value.Length / 2; string firstPart = value.Substring(0, splitIndex); string secondPart = value.Substring(splitIndex); return(string.Format(CultureInfo.InvariantCulture, template, firstPart + "<!--middle--> \n\t<?middle?>" + secondPart)); } }, // Element before causes a failure new ElementValueTestValue { XmlValueCreator = (template, value) => string.Format(CultureInfo.InvariantCulture, template, "<some/>" + value), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element") }, // Element after causes a failure new ElementValueTestValue { XmlValueCreator = (template, value) => string.Format(CultureInfo.InvariantCulture, template, value + "<some/>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element") } }; var testDescriptors = targets.SelectMany(target => values.Select(value => { return(new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = target.PayloadElement(value.XmlValueCreator), ExpectedException = value.ExpectedException }); })); this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.AtomFormatConfigurations.Where(tc => !tc.IsRequest), (testDescriptor, testConfiguration) => { testDescriptor.RunTest(testConfiguration); }); }
public void TopLevelErrorTest() { // we don't allow extra properties at the top-level, so the only thing to test is extra properties on inner errors IEnumerable <PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { // extra properties in inner error new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError()) .JsonRepresentation("{ \"error\": { \"innererror\": { \"foo\": \"bar\" } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("msg1")) .JsonRepresentation("{ \"error\": { \"innererror\": { \"message\": \"msg1\", \"foo\": \"bar\" } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("msg1")) .JsonRepresentation("{ \"error\": { \"innererror\": { \"foo\": \"bar\", \"message\": \"msg1\" } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("msg1")) .JsonRepresentation("{ \"error\": { \"innererror\": { \"foo1\": \"bar1\", \"message\": \"msg1\", \"foo2\": \"bar2\" } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { // NOTE: in JSON, we don't fail on unrecognized duplicate properties, but we do in JSON light. DebugDescription = "Unrecognized properties should fail if duplicated.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("msg1")) .JsonRepresentation("{ \"error\": { \"innererror\": { \"foo\": \"bar1\", \"message\": \"msg1\", \"foo\": \"bar2\" } } }"), ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed", "foo") }, // extra properties in nested inner error new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(PayloadBuilder.InnerError())) .JsonRepresentation("{ \"error\": { \"innererror\": { \"internalexception\": { \"foo\": \"bar\" } } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(PayloadBuilder.InnerError().Message("msg1"))) .JsonRepresentation("{ \"error\": { \"innererror\": { \"internalexception\": { \"message\": \"msg1\", \"foo\": \"bar\" } } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(PayloadBuilder.InnerError().Message("msg1"))) .JsonRepresentation("{ \"error\": { \"innererror\": { \"internalexception\": { \"foo\": \"bar\", \"message\": \"msg1\" } } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(PayloadBuilder.InnerError().Message("msg1"))) .JsonRepresentation("{ \"error\": { \"innererror\": { \"internalexception\": { \"foo1\": \"bar1\", \"message\": \"msg1\", \"foo2\": \"bar2\" } } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Unrecognized properties in nested inner error should fail if duplicated.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(PayloadBuilder.InnerError().Message("msg1"))) .JsonRepresentation("{ \"error\": { \"innererror\": { \"internalexception\": { \"foo\": \"bar1\", \"message\": \"msg1\", \"foo\": \"bar2\" } } } }"), ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed", "foo") }, }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.JsonLightFormatConfigurations.Where(tc => !tc.IsRequest), TestReaderUtils.ODataBehaviorKinds, (testDescriptor, testConfiguration, behavior) => { // These descriptors are already tailored specifically for Json Light and // do not require normalization. testDescriptor.TestDescriptorNormalizers.Clear(); testDescriptor.RunTest(testConfiguration.CloneAndApplyBehavior(behavior)); }); }
public void TopLevelErrorAnnotationsTest() { IEnumerable <PayloadReaderTestDescriptor> testDescriptors = new PayloadReaderTestDescriptor[] { #region "error" object scope new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Should fail on duplicate custom instance annotations inside the \"error\" object.", PayloadElement = PayloadBuilder.Error() .JsonRepresentation(@" { ""error"": { ""@cn.foo"": ""ignored"", ""@cn.foo"": ""something else"" } }"), ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed", "cn.foo") }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Custom property annotation inside the \"error\" object should be ignored.", PayloadElement = PayloadBuilder.Error().Code("123") .JsonRepresentation(@" { ""error"": { ""*****@*****.**"": ""ignored"", ""code"": ""123"" } }"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Should fail on duplicates of custom property annotation inside the \"error\" object should be ignored.", PayloadElement = PayloadBuilder.Error().Code("123") .JsonRepresentation(@" { ""error"": { ""*****@*****.**"": ""ignored"", ""*****@*****.**"": ""something else"", ""code"": ""123"" } }"), ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed", "cn.foo", "code"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Property annotation without property inside the \"error\" object should fail.", PayloadElement = PayloadBuilder.Error() .JsonRepresentation(@" { ""error"": { ""*****@*****.**"": ""fail"" } }"), ExpectedException = ODataExpectedExceptions.ODataException("ODataJsonLightErrorDeserializer_PropertyAnnotationWithoutPropertyForError", "code") }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "OData instance annotations inside the \"error\" object should be ignored.", PayloadElement = PayloadBuilder.Error() .JsonRepresentation(@" { ""error"": { ""@odata.foo"": ""fail"" } }"), ExpectedException = (ExpectedException)null }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "OData property annotations inside the \"error\" object should be ignored.", PayloadElement = PayloadBuilder.Error().Code("123") .JsonRepresentation(@" { ""error"": { ""*****@*****.**"": ""fail"", ""code"": ""123"" } }"), ExpectedException = (ExpectedException)null }, #endregion "error" object scope #region "innererror" object scope new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Custom instance annotation inside the \"innererror\" object should be ignored.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError()) .JsonRepresentation(@" { ""error"": { ""innererror"": { ""@cn.foo"": ""ignored"" } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Should fail on duplicate custom instance annotations inside the \"innererror\" object.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError()) .JsonRepresentation(@" { ""error"": { ""innererror"": { ""@cn.foo"": ""ignored"", ""@cn.foo"": ""something else"" } } }"), ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed", "cn.foo") }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Custom property annotations inside the \"innererror\" object should be ignored.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("msg")) .JsonRepresentation(@" { ""error"": { ""innererror"": { ""*****@*****.**"": ""ignored"", ""message"": ""msg"" } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Should fail on duplicate custom property annotations inside the \"innererror\" object.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("msg")) .JsonRepresentation(@" { ""error"": { ""innererror"": { ""*****@*****.**"": ""ignored"", ""*****@*****.**"": ""something else"", ""message"": ""msg"" } } }"), ExpectedException = ODataExpectedExceptions.ODataException("DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed", "cn.foo", "message") }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Should not fail on custom instance annotations with the same name at different nesting levels inside the \"innererror\" object.", PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().InnerError(PayloadBuilder.InnerError())) .JsonRepresentation(@" { ""error"": { ""@cn.foo"": ""ignored"", ""innererror"": { ""@cn.foo"": ""ignored"", ""internalexception"": { ""@cn.foo"": ""ignored"" } } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Should not fail on custom property annotations with the same name at different nesting levels inside the \"innererror\" object.", PayloadElement = PayloadBuilder.Error() .Message(string.Empty) .InnerError(PayloadBuilder.InnerError() .Message("msg") .InnerError(PayloadBuilder.InnerError() .Message("msg"))) .JsonRepresentation(@" { ""error"": { ""*****@*****.**"": ""ignored"", ""message"": """", ""innererror"": { ""*****@*****.**"": ""ignored"", ""message"": ""msg"", ""internalexception"": { ""*****@*****.**"": ""ignored"", ""message"": ""msg"" } } } }"), }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Property annotation without property inside the \"innererror\" object should fail.", PayloadElement = PayloadBuilder.Error() .JsonRepresentation(@" { ""error"": { ""innererror"": { ""*****@*****.**"": ""fail"" } } }"), ExpectedException = ODataExpectedExceptions.ODataException("ODataJsonLightErrorDeserializer_PropertyAnnotationWithoutPropertyForError", "message") }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "OData instance annotations inside the \"innererror\" object should be ignored.", PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload()) .JsonRepresentation(@" { ""error"": { ""innererror"": { ""@odata.foo"": ""fail"" } } }"), ExpectedException = (ExpectedException)null }, new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Unknown odata property annotations inside the \"innererror\" object should be ignored.", PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload().Message("msg")) .JsonRepresentation(@" { ""error"": { ""innererror"": { ""*****@*****.**"": ""bar"", ""message"": ""msg"" } } }"), ExpectedException = (ExpectedException)null }, #endregion "innererror" object scope #region "message" object scope new PayloadReaderTestDescriptor(this.Settings) { DebugDescription = "Read empty error message.", PayloadElement = PayloadBuilder.Error().Message(string.Empty) .JsonRepresentation(@" { ""error"": { ""message"": """" } }"), }, #endregion "message" object scope }; this.CombinatorialEngineProvider.RunCombinations( testDescriptors, this.ReaderTestConfigurationProvider.JsonLightFormatConfigurations.Where(tc => !tc.IsRequest), TestReaderUtils.ODataBehaviorKinds, (testDescriptor, testConfiguration, behavior) => { // These descriptors are already tailored specifically for Json Light and // do not require normalization. testDescriptor.TestDescriptorNormalizers.Clear(); testDescriptor.RunTest(testConfiguration.CloneAndApplyBehavior(behavior)); }); }
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> /// Creates invalid error representations in ATOM (e.g., extra properties where they are not allowed, /// invalid property value types, etc.) /// </summary> /// <param name="settings">The test descriptor settings to use for the generated <see cref="PayloadReaderTestDescriptor"/>.</param> /// <returns>An enumerable of <see cref="PayloadReaderTestDescriptor"/> representing the invalid error payloads.</returns> private static IEnumerable <PayloadReaderTestDescriptor> CreateInvalidErrorDescriptors(PayloadReaderTestDescriptor.Settings settings) { return(new PayloadReaderTestDescriptor[] { #region Duplicate error elements // duplicate 'm:code' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().Code("ErrorCode").XmlRepresentation("<m:error><m:code>ErrorCode</m:code><m:code>ErrorCode2</m:code></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleErrorElementsWithSameName", "code") }, // duplicate 'm:message' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().Message("ErrorMessage").XmlRepresentation("<m:error><m:message>ErrorMessage</m:message><m:message>ErrorMessage2</m:message></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleErrorElementsWithSameName", "message") }, // duplicate 'm:innererror' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload()).XmlRepresentation("<m:error><m:innererror></m:innererror><m:innererror></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleErrorElementsWithSameName", "innererror") }, // duplicate (inner) 'm:message' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload().Message("InnerMessage")).XmlRepresentation("<m:error><m:innererror><m:message>InnerMessage</m:message><m:message>InnerMessage2</m:message></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleInnerErrorElementsWithSameName", "message") }, // duplicate (inner) 'm:type' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload().TypeName("TypeName")).XmlRepresentation("<m:error><m:innererror><m:type>TypeName</m:type><m:type>TypeName2</m:type></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleInnerErrorElementsWithSameName", "type") }, // duplicate (inner) 'm:stacktrace' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload().StackTrace("StackTrace")).XmlRepresentation("<m:error><m:innererror><m:stacktrace>StackTrace</m:stacktrace><m:stacktrace>StackTrace2</m:stacktrace></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleInnerErrorElementsWithSameName", "stacktrace") }, // duplicate (inner) 'm:internalexception' element new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(new ODataInternalExceptionPayload().InnerError(new ODataInternalExceptionPayload())).XmlRepresentation("<m:error><m:innererror><m:internalexception></m:internalexception><m:internalexception></m:internalexception></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomErrorDeserializer_MultipleInnerErrorElementsWithSameName", "internalexception") }, #endregion Duplicate error elements #region Element content in string elements // Element content in <m:code> new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().Code("ErrorCode").XmlRepresentation("<m:error><m:code><foo></foo>ErrorCode<bar /></m:code></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element"), }, // Element content in <m:message> new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().Message("Message").XmlRepresentation("<m:error><m:message><foo></foo>Message<bar /></m:message></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element"), }, // Element content in <m:message> (inner) new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().Message("Message")) .XmlRepresentation("<m:error><m:innererror><m:message><foo></foo>Message<bar /></m:message></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element"), }, // Element content in <m:type> (inner) new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().TypeName("Type")) .XmlRepresentation("<m:error><m:innererror><m:type><foo></foo>TypeName<bar /></m:type></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element"), }, // Element content in <m:stacktrace> (inner) new PayloadReaderTestDescriptor(settings) { PayloadElement = PayloadBuilder.Error().InnerError(PayloadBuilder.InnerError().StackTrace("StackTrace")) .XmlRepresentation("<m:error><m:innererror><m:stacktrace><foo></foo>StackTrace<bar /></m:stacktrace></m:innererror></m:error>"), ExpectedException = ODataExpectedExceptions.ODataException("XmlReaderExtension_InvalidNodeInStringValue", "Element"), }, #endregion Element content in string elements }); }