internal bool CompareProperties(PayloadObject payloadObject, object element, bool throwOnFailure) { // Verify resource properties and navigation foreach (PayloadProperty property in payloadObject.PayloadProperties) { if (property is PayloadComplexProperty) { PayloadComplexProperty payloadProperty = (PayloadComplexProperty)property; if (!this.CompareComplexType(payloadProperty, element, true)) { if (throwOnFailure) { throw new TestFailedException("Value for complex property '" + property.Name + "' does not batch baseline"); } return(false); } } else if (property is PayloadSimpleProperty) { PayloadSimpleProperty payloadProperty = (PayloadSimpleProperty)property; if (!this.CompareSimpleType(payloadProperty, element, true)) { if (throwOnFailure) { throw new TestFailedException("Value for simple property '" + property.Name + "' does not batch baseline"); } return(false); } } } return(true); }
internal PayloadComplexProperty parseComplexObject(PayloadObject parent, JSField field) { PayloadComplexProperty payloadProperty = new PayloadComplexProperty(parent); payloadProperty.Name = field.Name; JSObject fieldValue = (JSObject)field.GetValue(field); FieldInfo[] fieldInfo = fieldValue.GetFields(BindingFlags.Default); for (int j = 0; j < fieldInfo.Length; j++) { JSField currentField = (JSField)fieldInfo[j]; if (currentField.GetValue(currentField) is JSObject) { PayloadComplexProperty payloadComplexProperty = this.parseComplexObject(parent, (JSField)fieldInfo[j]); payloadProperty.PayloadProperties.Add(payloadComplexProperty.Name, payloadComplexProperty); } else { PayloadProperty payloadSimpleProperty = this.parseSimpleObject(parent, (JSField)fieldInfo[j]); payloadProperty.PayloadProperties.Add(payloadSimpleProperty.Name, payloadSimpleProperty); } } return(payloadProperty); }
internal void CompareObjects(PayloadObject payloadObject, object element) { bool found; foreach (PayloadObject nestedObject in payloadObject.PayloadObjects) { if (nestedObject.Deferred) { // do something } else if (nestedObject.Reference) { object nestedElement = LoadReference(element, nestedObject.Name); //this.CompareUri(referenceObject.Uri, referenceObject.Id, referenceObject.Name, nestedObject.Name); this.CompareProperties(nestedObject, nestedElement, true); this.CompareObjects(nestedObject, nestedElement); } else { // Call load on nested element List <object> enumerableList = LoadCollection(element, nestedObject.Name).OfType <object>().ToList(); Compare(enumerableList, nestedObject.PayloadObjects, true); } } }
private void VerifyInsertResponse(ResourceType type, PayloadObject inserted, PayloadObject returned) { // need to 'follow' deferred links to ensure that they're correct // doesn't need to match exactly AstoriaTestLog.AreEqual(inserted.Type, returned.Type, "Types do not match"); VerifyProperties(type, inserted, returned, true, (rp => !rp.Facets.ServerGenerated)); }
private void VerifyQueryResponse(ResourceType type, PayloadObject fromInsert, PayloadObject fromQuery) { bool keyShouldMatch = true; if (type.Key.Properties.Any(p => p.Facets.FixedLength)) { foreach (NodeProperty property in type.Key.Properties.Where(p => p.Facets.FixedLength)) { // this may not always be correct for all types, but it seems to work most of the time; int length; if (property.Facets.MaxSize.HasValue) { length = property.Facets.MaxSize.Value; } else if (property.Type == Clr.Types.Decimal) { length = property.Facets.Precision.Value + property.Facets.Scale.Value; } else { continue; } string value = null; if (fromInsert.PayloadProperties.Any(p => p.Name == property.Name)) { value = (fromInsert[property.Name] as PayloadSimpleProperty).Value; } else { value = fromInsert.CustomEpmMappedProperties[property.Name]; } if (value != null && value.Length < length) { keyShouldMatch = false; } } } if (keyShouldMatch) { AstoriaTestLog.AreEqual(fromInsert.AbsoluteUri, fromQuery.AbsoluteUri, "fromInsert.AbsoluteUri != fromQuery.AbsoluteUri", false); } else { AstoriaTestLog.IsFalse(fromInsert.AbsoluteUri == fromQuery.AbsoluteUri, "fromInsert.AbsoluteUri == fromQuery.AbsoluteUri, despite fixed-length string"); } // leave it to the concurrency tests to check the more involved etags if (!type.Properties.Any(p => p.Facets.ConcurrencyModeFixed && p.Facets.FixedLength)) { AstoriaTestLog.AreEqual(fromInsert.ETag, fromQuery.ETag, "fromInsert.ETag != fromQuery.ETag", false); } VerifyProperties(type, fromInsert, fromQuery, false, rp => true); }
internal PayloadObject ParseUriNode(XElement node) { PayloadObject po = new PayloadObject(this); PayloadSimpleProperty property = new PayloadSimpleProperty(po); property.Value = node.Value; property.Name = node.Name.LocalName; po.Name = node.Name.LocalName; po.PayloadProperties.Add(property); return(po); }
protected static bool TryGetSingleObjectFromPayload(CommonPayload payload, out PayloadObject payloadObject) { List<PayloadObject> list = payload.Resources as List<PayloadObject>; if (list == null || list.Count != 1) { payloadObject = null; return false; } payloadObject = list[0]; return true; }
private void Compare(IList <object> baselineObjects, IList <PayloadObject> payloadObjects, bool ignoreOrder) { AstoriaTestLog.AreEqual(baselineObjects.Count, payloadObjects.Count, "Count of baseline not equal to returned elements.", false); for (int position = 0; position < baselineObjects.Count; position++) { PayloadObject fromPayload = payloadObjects[position]; object fromBaseline = null; if (ignoreOrder) { foreach (object entity in baselineObjects) { if (this.CompareProperties(fromPayload, entity, false)) { fromBaseline = entity; break; } } if (fromBaseline == null) { throw new TestFailedException("Could not find matching entity"); } else { baselineObjects.Remove(fromBaseline); } } else { fromBaseline = baselineObjects[position]; try { this.CompareProperties(fromPayload, fromBaseline, true); } catch (Exception e) { throw new TestFailedException("Payload properties do not match baseline for entity at position " + position + " in payload", null, null, e); } } try { this.CompareObjects(fromPayload, fromBaseline); } catch (Exception e) { throw new TestFailedException("Payload objects do not match baseline for entity at position " + position + " in payload", null, null, e); } } }
private void ParseResults(string payload) { if (payload == null) { this.Value = null; return; } try { document = XDocument.Parse(payload); } catch (Exception e) { this.Value = payload; return; } XElement xmlData = document.Root; if (xmlData.Name.LocalName == "feed") { this.Resources = this.ParseFeed(xmlData); } else if (xmlData.Name.LocalName == "entry") { this.Resources = this.ParseSingleEntry(xmlData); } else if (xmlData.Name.LocalName == "links") { this.Resources = this.ParseLinks(xmlData); } else if (xmlData.Name.LocalName == "uri") { this.Resources = new List <PayloadObject>() { this.ParseUriNode(xmlData) } } ; else { PayloadObject payloadObject = new PayloadObject(this); if (xmlData.HasElements) { this.Resources = this.ParseComplexProperty(payloadObject, xmlData); } else { this.Resources = this.ParseSimpleProperty(payloadObject, xmlData); } } }
protected static bool TryGetSingleObjectFromPayload(CommonPayload payload, out PayloadObject payloadObject) { List <PayloadObject> list = payload.Resources as List <PayloadObject>; if (list == null || list.Count != 1) { payloadObject = null; return(false); } payloadObject = list[0]; return(true); }
public static KeyExpression ConstructKey(ResourceContainer container, PayloadObject entity) { Dictionary <string, object> properties = new Dictionary <string, object>(); ResourceType type = container.BaseType; if (entity.Type != type.Namespace + "." + type.Name) { type = container.ResourceTypes.SingleOrDefault(rt => rt.Namespace + "." + rt.Name == entity.Type); if (type == null) { AstoriaTestLog.FailAndThrow("Could not find resource type for payload type value: " + entity.Type); } } foreach (ResourceProperty property in type.Properties.OfType <ResourceProperty>()) { if (property.IsNavigation || property.IsComplexType) { continue; } string propertyName = property.Name; string valueString; if (entity.PayloadProperties.Any(p => p.Name == propertyName)) { PayloadSimpleProperty simpleProperty = entity[propertyName] as PayloadSimpleProperty; if (simpleProperty == null) { continue; } valueString = simpleProperty.Value; } else { continue; } object value = CommonPayload.DeserializeStringToObject(valueString, property.Type.ClrType, false, entity.Format); if (value is DateTime && entity.Format == SerializationFormatKind.JSON) { // TODO: this is because the server will make any JSON datetime into UTC, and currently we always send 'unspecified' values value = new DateTime(((DateTime)value).Ticks, DateTimeKind.Unspecified); } properties[propertyName] = value; } return(new KeyExpression(container, type, properties)); }
public static KeyExpression ConstructKey(ResourceContainer container, PayloadObject entity) { Dictionary<string, object> properties = new Dictionary<string, object>(); ResourceType type = container.BaseType; if (entity.Type != type.Namespace + "." + type.Name) { type = container.ResourceTypes.SingleOrDefault(rt => rt.Namespace + "." + rt.Name == entity.Type); if (type == null) AstoriaTestLog.FailAndThrow("Could not find resource type for payload type value: " + entity.Type); } foreach (ResourceProperty property in type.Properties.OfType<ResourceProperty>()) { if (property.IsNavigation || property.IsComplexType) continue; string propertyName = property.Name; string valueString; if (entity.PayloadProperties.Any(p => p.Name == propertyName)) { PayloadSimpleProperty simpleProperty = entity[propertyName] as PayloadSimpleProperty; if (simpleProperty == null) continue; valueString = simpleProperty.Value; } else { continue; } object value = CommonPayload.DeserializeStringToObject(valueString, property.Type.ClrType, false, entity.Format); if (value is DateTime && entity.Format == SerializationFormatKind.JSON) { // TODO: this is because the server will make any JSON datetime into UTC, and currently we always send 'unspecified' values value = new DateTime(((DateTime)value).Ticks, DateTimeKind.Unspecified); } properties[propertyName] = value; } return new KeyExpression(container, type, properties); }
internal PayloadSimpleProperty parseSimpleObject(PayloadObject parent, JSField field) { PayloadSimpleProperty payloadProperty = new PayloadSimpleProperty(parent); payloadProperty.Name = field.Name; object val = field.GetValue(field); if (val is System.DBNull) { payloadProperty.Value = null; payloadProperty.Type = null; payloadProperty.IsNull = true; } else { payloadProperty.Type = AstoriaUnitTests.Data.TypeData.FindForType(val.GetType()).GetEdmTypeName(); payloadProperty.Value = ConvertJsonValue(val); payloadProperty.IsNull = false; } return(payloadProperty); }
private void ParseResults(string payload) { if (payload == null) { this.Value = null; return; } try { document = XDocument.Parse(payload); } catch (Exception e) { this.Value = payload; return; } XElement xmlData = document.Root; if (xmlData.Name.LocalName == "feed") this.Resources = this.ParseFeed(xmlData); else if (xmlData.Name.LocalName == "entry") this.Resources = this.ParseSingleEntry(xmlData); else if (xmlData.Name.LocalName == "links") this.Resources = this.ParseLinks(xmlData); else if (xmlData.Name.LocalName == "uri") this.Resources = new List<PayloadObject>() { this.ParseUriNode(xmlData) }; else { PayloadObject payloadObject = new PayloadObject(this); if (xmlData.HasElements) this.Resources = this.ParseComplexProperty(payloadObject, xmlData); else this.Resources = this.ParseSimpleProperty(payloadObject, xmlData); } }
internal PayloadComplexProperty ParseComplexProperty(PayloadObject parent, XElement xmlData) { PayloadComplexProperty payloadProperty = new PayloadComplexProperty(parent); payloadProperty.Name = xmlData.Name.LocalName; XAttribute nullAttribute = xmlData.Attribute(m + "null"); if (nullAttribute != null && nullAttribute.Value == "true") { payloadProperty.IsNull = true; } XAttribute typeAttribute = xmlData.Attribute(m + "type"); if (typeAttribute != null) { payloadProperty.Type = typeAttribute.Value; } foreach (XElement property in xmlData.Elements()) { PayloadProperty subProperty; if (property.HasElements) { subProperty = ParseComplexProperty(parent, property); } else { subProperty = ParseSimpleProperty(parent, property); } payloadProperty.PayloadProperties.Add(subProperty.Name, subProperty); } return(payloadProperty); }
internal PayloadSimpleProperty ParseSimpleProperty(PayloadObject parent, XElement xmlData) { PayloadSimpleProperty payloadProperty = new PayloadSimpleProperty(parent); payloadProperty.Name = xmlData.Name.LocalName; payloadProperty.Value = xmlData.Value; XAttribute nullAttribute = xmlData.Attribute(m + "null"); if (nullAttribute != null && nullAttribute.Value == "true") { payloadProperty.Value = null; payloadProperty.IsNull = true; } XAttribute typeAttribute = xmlData.Attribute(m + "type"); if (typeAttribute != null) { payloadProperty.Type = typeAttribute.Value; } return(payloadProperty); }
private void ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty itemProperty, XElement xmlData, PayloadObject payloadObject) { XElement element = xmlData.Element(atom + itemProperty.ToString().ToLowerInvariant()); if (element != null) { var value = element.Value; XAttribute nullAttribute = element.Attribute(m + "null"); if (nullAttribute != null && nullAttribute.Value == "true") { value = null; } payloadObject.SyndicationItemProperties[itemProperty] = value; } }
internal static KeyedResourceInstance CreateKeyedResourceInstanceFromPayloadObject(ResourceContainer container, ResourceType resourceType, PayloadObject payloadObject) { List <ResourceInstanceProperty> properties = new List <ResourceInstanceProperty>(); List <ResourceInstanceProperty> keyProperties = new List <ResourceInstanceProperty>(); foreach (ResourceProperty property in resourceType.Properties.OfType <ResourceProperty>()) { if (property.IsNavigation) { continue; } if (property.IsComplexType) { PayloadComplexProperty fromPayload = payloadObject[property.Name] as PayloadComplexProperty; properties.Add(ConvertComplexPayloadObjectToComplexProperty(property, fromPayload)); } else { string stringValue; if (payloadObject.PayloadProperties.Any(p => p.Name == property.Name)) { PayloadSimpleProperty fromPayload = payloadObject[property.Name] as PayloadSimpleProperty; stringValue = fromPayload.Value; } else { if (!payloadObject.CustomEpmMappedProperties.TryGetValue(property.Name, out stringValue)) { stringValue = null; } } ResourceInstanceProperty newProperty = null; object val = CommonPayload.DeserializeStringToObject(stringValue, property.Type.ClrType, false, payloadObject.Format); newProperty = new ResourceInstanceSimpleProperty(property.Name, new NodeValue(val, property.Type)); if (property.PrimaryKey != null) { keyProperties.Add(newProperty); } else { properties.Add(newProperty); } } } ResourceInstanceKey key = new ResourceInstanceKey(container, resourceType, keyProperties.ToArray()); return(new KeyedResourceInstance(key, properties.ToArray())); }
private PayloadObject parseJsonObject(JSObject jsObject) { PayloadObject payloadObject = new PayloadObject(this); FieldInfo[] fields = jsObject.GetFields(BindingFlags.Default); for (int i = 0; i < fields.Length; i++) { JSField field = (JSField)fields[i]; var value = field.GetValue(field); if (value is ArrayObject) { PayloadObject payloadNestedParentObject = new PayloadObject(this); payloadNestedParentObject.Name = field.Name; ArrayObject nestedPayloadObjects = (ArrayObject)field.GetValue(field); payloadNestedParentObject.PayloadObjects.AddRange(this.ParseJsonArray(nestedPayloadObjects)); foreach (PayloadObject po in payloadNestedParentObject.PayloadObjects) { po.Name = field.Name; } payloadObject.PayloadObjects.Add(payloadNestedParentObject); } else if (value is JSObject) { if (field.Name == "__metadata") { payloadObject.Uri = this.GetArrayString(field, "uri"); payloadObject.Type = this.GetArrayString(field, "type"); string etag = this.GetArrayString(field, "etag"); if (etag != null) { payloadObject.ETag = etag; } } else { JSField firstChild = this.GetArrayField(field, 0); if (firstChild != null && firstChild.Name == v2JsonResultsField) { PayloadObject payloadNestedParentObject = new PayloadObject(this); payloadNestedParentObject.Name = field.Name; ArrayObject nestedPayloadObjects = (ArrayObject)firstChild.GetValue(firstChild); payloadNestedParentObject.PayloadObjects.AddRange(this.ParseJsonArray(nestedPayloadObjects)); foreach (PayloadObject po in payloadNestedParentObject.PayloadObjects) { po.Name = field.Name; } payloadObject.PayloadObjects.Add(payloadNestedParentObject); } else if (firstChild != null && firstChild.Name == "__deferred") // Deferred reference/collection { PayloadObject deferredObject = new PayloadObject(this); deferredObject.Name = field.Name; deferredObject.Uri = this.GetArrayString(firstChild, "uri"); deferredObject.Deferred = true; payloadObject.PayloadObjects.Add(deferredObject); } else if (firstChild != null && firstChild.Name == "__mediaresource") { PayloadNamedStream stream = new PayloadNamedStream(); stream.Name = field.Name; stream.ContentType = this.GetArrayString(firstChild, "content-type"); stream.EditLink = this.GetArrayString(firstChild, "edit_media"); stream.SelfLink = this.GetArrayString(firstChild, "media_src"); stream.ETag = this.GetArrayString(firstChild, "etag"); payloadObject.NamedStreams.Add(stream); } else { JSObject objectValue = (JSObject)field.GetValue(field); var objectValueFields = objectValue.GetFields(BindingFlags.Default); if (objectValueFields.Any(f => f.Name == "__metadata" && GetArrayString((JSField)f, "uri") != null)) { PayloadObject referencePayloadObject = parseJsonObject(objectValue); referencePayloadObject.Name = field.Name; referencePayloadObject.Reference = true; payloadObject.PayloadObjects.Add(referencePayloadObject); } else { PayloadComplexProperty payloadProperty = this.parseComplexObject(payloadObject, field); // Complex object payloadObject.PayloadProperties.Add(payloadProperty); } } } } else { PayloadProperty payloadProperty = this.parseSimpleObject(payloadObject, field); payloadObject.PayloadProperties.Add(payloadProperty); } } return(payloadObject); }
private void VerifyProperties(ResourceType type, PayloadObject inserted, PayloadObject returned, bool missingInsertPropertiesOk, Func<ResourceProperty, bool> strictEquality) { List<string> propertyNames = inserted.PayloadProperties.Union(returned.PayloadProperties).Select(p => p.Name).ToList(); propertyNames.AddRange(inserted.CustomEpmMappedProperties.Keys); propertyNames.AddRange(returned.CustomEpmMappedProperties.Keys); foreach (string propertyName in propertyNames.Distinct()) { PayloadProperty insertedProperty; if(inserted.Format == SerializationFormatKind.JSON) //in JSON the first one wins insertedProperty = inserted.PayloadProperties.FirstOrDefault(p => p.Name == propertyName); else //in xml the last one wins insertedProperty = inserted.PayloadProperties.LastOrDefault(p => p.Name == propertyName); bool insertHadProperty = insertedProperty != null; PayloadProperty returnedProperty = returned.PayloadProperties.LastOrDefault(p => p.Name == propertyName); ; bool returnedHadProperty = returnedProperty != null; ResourceProperty property = type.Properties.OfType<ResourceProperty>().SingleOrDefault(p => p.Name == propertyName); if (property == null || !property.Facets.IsDeclaredProperty) { if (!type.Facets.IsOpenType) { string error = "included dynamic property '" + propertyName + "' despite '" + type.Name + "' not being an open type"; if (insertHadProperty && returnedHadProperty) AstoriaTestLog.FailAndThrow("Both the inserted and returned objects " + error); else if (insertHadProperty) AstoriaTestLog.FailAndThrow("The inserted object " + error); else if (returnedHadProperty) AstoriaTestLog.FailAndThrow("The returned object " + error); } else { if (insertHadProperty && returnedHadProperty) { CompareDynamicPropertyValues(insertedProperty, returnedProperty); } else if (insertHadProperty) { // only acceptable if inserted value was null if (insertedProperty.IsNull) AstoriaTestLog.FailAndThrow("Returned object missing non-null dynamic property '" + propertyName + "'"); } } } else { if (property.IsNavigation) { // the insert payload may not specify this property //PayloadObject insertedObject = inserted.PayloadObjects.SingleOrDefault(o => o.Name == property.Name); PayloadObject returnedObject = returned.PayloadObjects.Single(o => o.Name == property.Name); // returned thing should be deferred whether its a reference or not AstoriaTestLog.AreEqual(true, returnedObject.Deferred, "!returnedObject.Deferred", false); // TODO: verify only expected links are present (based on uri and payload values as well) } else { if (insertHadProperty && returnedHadProperty) { try { ComparePropertyValues(property, insertedProperty, returnedProperty, strictEquality(property)); } catch (Exception e) { throw new TestFailedException("Value of property '" + property.Name + "' does not match inserted value", null, null, e); } } else if (insertHadProperty) { AstoriaTestLog.FailAndThrow("Returned object unexpectedly missing declared property '" + propertyName + "'"); } else if (returnedHadProperty) { if (missingInsertPropertiesOk) AstoriaTestLog.WriteLineIgnore("Ignoring missing declared property '" + propertyName + "' in insert payload"); else AstoriaTestLog.FailAndThrow("Inserted object unexpectedly missing declared property '" + propertyName + "'"); } } } } }
private void VerifyQueryResponse(ResourceType type, PayloadObject fromInsert, PayloadObject fromQuery) { bool keyShouldMatch = true; if (type.Key.Properties.Any(p => p.Facets.FixedLength)) { foreach (NodeProperty property in type.Key.Properties.Where(p => p.Facets.FixedLength)) { // this may not always be correct for all types, but it seems to work most of the time; int length; if (property.Facets.MaxSize.HasValue) length = property.Facets.MaxSize.Value; else if (property.Type == Clr.Types.Decimal) length = property.Facets.Precision.Value + property.Facets.Scale.Value; else continue; string value = null; if (fromInsert.PayloadProperties.Any(p => p.Name == property.Name)) { value = (fromInsert[property.Name] as PayloadSimpleProperty).Value; } else { value = fromInsert.CustomEpmMappedProperties[property.Name]; } if (value != null && value.Length < length) keyShouldMatch = false; } } if (keyShouldMatch) AstoriaTestLog.AreEqual(fromInsert.AbsoluteUri, fromQuery.AbsoluteUri, "fromInsert.AbsoluteUri != fromQuery.AbsoluteUri", false); else AstoriaTestLog.IsFalse(fromInsert.AbsoluteUri == fromQuery.AbsoluteUri, "fromInsert.AbsoluteUri == fromQuery.AbsoluteUri, despite fixed-length string"); // leave it to the concurrency tests to check the more involved etags if (!type.Properties.Any(p => p.Facets.ConcurrencyModeFixed && p.Facets.FixedLength)) AstoriaTestLog.AreEqual(fromInsert.ETag, fromQuery.ETag, "fromInsert.ETag != fromQuery.ETag", false); VerifyProperties(type, fromInsert, fromQuery, false, rp => true); }
internal PayloadComplexProperty parseComplexObject(PayloadObject parent, JSField field) { PayloadComplexProperty payloadProperty = new PayloadComplexProperty(parent); payloadProperty.Name = field.Name; JSObject fieldValue = (JSObject)field.GetValue(field); FieldInfo[] fieldInfo = fieldValue.GetFields(BindingFlags.Default); for (int j = 0; j < fieldInfo.Length; j++) { JSField currentField = (JSField)fieldInfo[j]; if (currentField.GetValue(currentField) is JSObject) { PayloadComplexProperty payloadComplexProperty = this.parseComplexObject(parent, (JSField)fieldInfo[j]); payloadProperty.PayloadProperties.Add(payloadComplexProperty.Name, payloadComplexProperty); } else { PayloadProperty payloadSimpleProperty = this.parseSimpleObject(parent, (JSField)fieldInfo[j]); payloadProperty.PayloadProperties.Add(payloadSimpleProperty.Name, payloadSimpleProperty); } } return payloadProperty; }
private PayloadObject parseJsonObject(JSObject jsObject) { PayloadObject payloadObject = new PayloadObject(this); FieldInfo[] fields = jsObject.GetFields(BindingFlags.Default); for (int i = 0; i < fields.Length; i++) { JSField field = (JSField)fields[i]; var value = field.GetValue(field); if (value is ArrayObject) { PayloadObject payloadNestedParentObject = new PayloadObject(this); payloadNestedParentObject.Name = field.Name; ArrayObject nestedPayloadObjects = (ArrayObject)field.GetValue(field); payloadNestedParentObject.PayloadObjects.AddRange(this.ParseJsonArray(nestedPayloadObjects)); foreach (PayloadObject po in payloadNestedParentObject.PayloadObjects) { po.Name = field.Name; } payloadObject.PayloadObjects.Add(payloadNestedParentObject); } else if (value is JSObject) { if (field.Name == "__metadata") { payloadObject.Uri = this.GetArrayString(field, "uri"); payloadObject.Type = this.GetArrayString(field, "type"); string etag = this.GetArrayString(field, "etag"); if (etag != null) { payloadObject.ETag = etag; } } else { JSField firstChild = this.GetArrayField(field, 0); if (firstChild != null && firstChild.Name == v2JsonResultsField) { PayloadObject payloadNestedParentObject = new PayloadObject(this); payloadNestedParentObject.Name = field.Name; ArrayObject nestedPayloadObjects = (ArrayObject)firstChild.GetValue(firstChild); payloadNestedParentObject.PayloadObjects.AddRange(this.ParseJsonArray(nestedPayloadObjects)); foreach (PayloadObject po in payloadNestedParentObject.PayloadObjects) { po.Name = field.Name; } payloadObject.PayloadObjects.Add(payloadNestedParentObject); } else if (firstChild != null && firstChild.Name == "__deferred") // Deferred reference/collection { PayloadObject deferredObject = new PayloadObject(this); deferredObject.Name = field.Name; deferredObject.Uri = this.GetArrayString(firstChild, "uri"); deferredObject.Deferred = true; payloadObject.PayloadObjects.Add(deferredObject); } else if (firstChild != null && firstChild.Name == "__mediaresource") { PayloadNamedStream stream = new PayloadNamedStream(); stream.Name = field.Name; stream.ContentType = this.GetArrayString(firstChild, "content-type"); stream.EditLink = this.GetArrayString(firstChild, "edit_media"); stream.SelfLink = this.GetArrayString(firstChild, "media_src"); stream.ETag = this.GetArrayString(firstChild, "etag"); payloadObject.NamedStreams.Add(stream); } else { JSObject objectValue = (JSObject)field.GetValue(field); var objectValueFields = objectValue.GetFields(BindingFlags.Default); if (objectValueFields.Any(f => f.Name == "__metadata" && GetArrayString((JSField)f, "uri") != null)) { PayloadObject referencePayloadObject = parseJsonObject(objectValue); referencePayloadObject.Name = field.Name; referencePayloadObject.Reference = true; payloadObject.PayloadObjects.Add(referencePayloadObject); } else { PayloadComplexProperty payloadProperty = this.parseComplexObject(payloadObject, field); // Complex object payloadObject.PayloadProperties.Add(payloadProperty); } } } } else { PayloadProperty payloadProperty = this.parseSimpleObject(payloadObject, field); payloadObject.PayloadProperties.Add(payloadProperty); } } return payloadObject; }
public static string ConstructETag(ResourceContainer container, PayloadObject entity) { KeyExpression key = ConstructKey(container, entity); return key.ETag; }
public PayloadSimpleProperty(PayloadObject parent) : base(parent) { }
// DO NOT INSTANTIATE THIS DIRECTLY. Use either CommonPayload.CreateCommonPayload or AstoriaResponse.CommonPayload internal JSONPayload(AstoriaRequestResponseBase rr) : base(rr) { string jsonString = this.RawPayload; if (jsonString == null) { this.Value = null; return; } jsonString = StripSecurityWrapper(jsonString); object jsonData = null; try { jsonData = Evaluator.EvalToObject("(" + jsonString + ")"); } catch (Exception e) { this.Value = jsonString; return; } if (jsonData is ArrayObject) { this.Resources = ParseJsonArray((ArrayObject)jsonData); } else if (jsonData is JSObject) { FieldInfo[] fields = ((JSObject)jsonData).GetFields(BindingFlags.Default); // v2-style array, with count/page if (fields.Any(field => field.Name == v2JsonResultsField)) { foreach (FieldInfo field in fields) { object value = field.GetValue(field); switch (field.Name) { case v2NextField: this.NextLink = value.ToString(); break; case v2CountField: this.Count = Convert.ToInt64(value.ToString()); break; case v2JsonResultsField: if (value is ArrayObject) { this.Resources = ParseJsonArray((ArrayObject)value); } else { AstoriaTestLog.FailAndThrow("Array expected in results field"); } break; default: AstoriaTestLog.FailAndThrow("Field '" + field.Name + "' unexpected"); break; } } } else if (fields.Any(field => field.Name == "__metadata")) { this.Resources = ParseSingleJsonObject((JSObject)jsonData); // entry } else { if (fields.Length > 1) { AstoriaTestLog.FailAndThrow("Single field expected for non-entry payload"); } FieldInfo field = fields[0]; object value = field.GetValue(field); PayloadObject payloadObject = new PayloadObject(this); PayloadProperty property; if (value is JSObject) { property = parseComplexObject(payloadObject, (JSField)field); } else { property = parseSimpleObject(payloadObject, (JSField)field); } if (property.Name != "uri") { this.Resources = property; } else { // this is to match the resulting structure for parsing links in ATOM / json collections PayloadObject temp = new PayloadObject(this); temp.Name = property.Name; temp.PayloadProperties.Add(property); this.Resources = new List <PayloadObject>() { temp }; } } } else { this.Value = jsonString; // must be $value } }
internal PayloadObject ParseEntry(XElement xmlData) { PayloadObject payloadObject = new PayloadObject(this); #region edit link XElement linkEdit = xmlData.Elements(atom + "link").SingleOrDefault(l => l.Attribute("rel") != null && l.Attribute("rel").Value == "edit"); if (linkEdit != null) { payloadObject.Uri = linkEdit.Attribute("href").Value; } #endregion #region id link XElement idNode = xmlData.Element(atom + "id"); if (idNode != null) { payloadObject.Uri = idNode.Value; } // TODO: compare the edit link to the ID node's value #endregion #region name XElement titleNode = xmlData.Parent; if (titleNode != null && titleNode.Name == m + "inline") { XAttribute titleAttribute = titleNode.Parent.Attribute("title"); if (titleAttribute != null) { payloadObject.Name = titleAttribute.Value; } } else if (titleNode != null) { titleNode = titleNode.Element(atom + "title"); if (titleNode != null) { payloadObject.Name = titleNode.Value; } } else if (linkEdit != null) { XAttribute titleAttribute = linkEdit.Attribute("title"); if (titleAttribute != null) { payloadObject.Name = titleAttribute.Value; } } #endregion #region type bool isMediaLink = false; XElement category = xmlData.Element(atom + "category"); ResourceType type = null; if (category != null) { XAttribute term = category.Attribute("term"); if (term != null) { payloadObject.Type = term.Value; type = Workspace.ServiceContainer.ResourceTypes.Single(rt => rt.Namespace + "." + rt.Name == term.Value); if (type.Facets.HasStream) { isMediaLink = true; } } } #endregion #region friendly feeds ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty.Title, xmlData, payloadObject); ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty.Summary, xmlData, payloadObject); ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty.Rights, xmlData, payloadObject); //This is the correct mapping for Friendly Feeds SyndicationItemProperty.Published XElement ffEntryPublishedNode = xmlData.Element(atom + "published"); if (ffEntryPublishedNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.Published] = ffEntryPublishedNode.Value; } //This is the correct mapping for Friendly Feeds SyndicationItemProperty.Updated XElement ffEntryUpdatedNode = xmlData.Element(atom + "updated"); if (ffEntryUpdatedNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.Updated] = ffEntryUpdatedNode.Value; } //This is the correct mapping for Friendly Feeds Author Node XElement ffEntryAuthorNode = xmlData.Element(atom + "author"); if (ffEntryAuthorNode != null) { //Friendly Feeds SyndicationItemProperty.AuthorEmail XElement ffEmailNode = ffEntryAuthorNode.Element(atom + "email"); if (ffEmailNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.AuthorEmail] = ffEmailNode.Value; } //Friendly Feeds SyndicationItemProperty.AuthorName XElement ffNameNode = ffEntryAuthorNode.Element(atom + "name"); if (ffNameNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.AuthorName] = ffNameNode.Value; } //Friendly Feeds SyndicationItemProperty.AuthorUri XElement ffUriNode = ffEntryAuthorNode.Element(atom + "uri"); if (ffUriNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.AuthorUri] = ffUriNode.Value; } } //This is the correct mapping for Friendly Feeds Contributor Node XElement ffEntryContributorNode = xmlData.Element(atom + "contributor"); if (ffEntryContributorNode != null) { //Friendly Feeds SyndicationItemProperty.ContributorEmail XElement ffEmailNode = ffEntryContributorNode.Element(atom + "email"); if (ffEmailNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.ContributorEmail] = ffEmailNode.Value; } //Friendly Feeds SyndicationItemProperty.ContributorName XElement ffNameNode = ffEntryContributorNode.Element(atom + "name"); if (ffNameNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.ContributorName] = ffNameNode.Value; } //Friendly Feeds SyndicationItemProperty.ContributorUri XElement ffUriNode = ffEntryContributorNode.Element(atom + "uri"); if (ffUriNode != null) { payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.ContributorUri] = ffUriNode.Value; } } #endregion #region etag if (xmlData.HasAttributes) { XAttribute etagNodeAttribute = xmlData.Attribute(m + "etag"); if (etagNodeAttribute != null) { payloadObject.ETag = etagNodeAttribute.Value; } } #endregion #region properties XElement content = xmlData.Element(atom + "content"); XElement properties = null; if (content != null) { XAttribute contentType = content.Attribute("type"); if (contentType != null) { if (!isMediaLink) { StringComparison comp; if (WasResponse) { comp = StringComparison.InvariantCulture; } else { comp = StringComparison.InvariantCultureIgnoreCase; } if (!contentType.Value.Equals("application/xml", comp)) { AstoriaTestLog.AreEqual("application/xml", contentType.Value, "Unexpected type on content element", true); } properties = content.Element(m + "properties"); } // TODO: save content type if its a media link } } if (isMediaLink) { properties = xmlData.Element(m + "properties"); } if (properties != null) { foreach (XElement element in properties.Elements()) { PayloadProperty property; if (element.HasElements) { property = ParseComplexProperty(payloadObject, element); } else { property = ParseSimpleProperty(payloadObject, element); } payloadObject.PayloadProperties.Add(property); } } #endregion #region links foreach (XElement link in xmlData.Elements(atom + "link")) { Uri linkRel = new Uri(link.Attribute("rel").Value, UriKind.RelativeOrAbsolute); if (linkRel.IsAbsoluteUri) { string linkRelValue = linkRel.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); if (linkRelValue.StartsWith(DataWebRelatedNamespace, StringComparison.Ordinal)) { XElement inlineTag = link.Element(m + "inline"); if (inlineTag != null) { PayloadObject nestedPayloadObject = new PayloadObject(this); nestedPayloadObject.Name = linkRelValue.Substring(DataWebRelatedNamespace.Length); string linkType = link.Attribute("type").Value; if (linkType.Contains("feed")) { if (inlineTag.HasElements) { nestedPayloadObject.PayloadObjects.AddRange(this.ParseFeed(inlineTag.Elements().Single())); } } else if (linkType.Contains("entry")) { if (inlineTag.HasElements) { nestedPayloadObject = this.ParseEntry(inlineTag.Elements().Single()); } nestedPayloadObject.Reference = true; } payloadObject.PayloadObjects.Add(nestedPayloadObject); } else { // deferred links PayloadObject deferredObject = new PayloadObject(this); deferredObject.Name = linkRelValue.Substring(DataWebRelatedNamespace.Length); if (link.Attribute("href") != null) { deferredObject.Uri = link.Attribute("href").Value; } deferredObject.Deferred = true; payloadObject.PayloadObjects.Add(deferredObject); } } else if (linkRelValue.StartsWith(DataWebMediaResourceNamespace)) { string name = linkRelValue.Substring(DataWebMediaResourceNamespace.Length); PayloadNamedStream namedStream = payloadObject.NamedStreams.SingleOrDefault(s => s.Name == name); if (namedStream == null) { namedStream = new PayloadNamedStream() { Name = name }; payloadObject.NamedStreams.Add(namedStream); } UpdateNamedStreamMetadata(link, namedStream); namedStream.SelfLink = link.Attribute("href").Value; } else if (linkRelValue.StartsWith(DataWebMediaResourceEditNamespace)) { string name = linkRelValue.Substring(DataWebMediaResourceEditNamespace.Length); PayloadNamedStream namedStream = payloadObject.NamedStreams.SingleOrDefault(s => s.Name == name); if (namedStream == null) { namedStream = new PayloadNamedStream() { Name = name }; payloadObject.NamedStreams.Add(namedStream); } UpdateNamedStreamMetadata(link, namedStream); namedStream.EditLink = link.Attribute("href").Value; } } } #endregion return(payloadObject); }
public static string ConstructETag(ResourceContainer container, PayloadObject entity) { KeyExpression key = ConstructKey(container, entity); return(key.ETag); }
internal PayloadSimpleProperty ParseSimpleProperty(PayloadObject parent, XElement xmlData) { PayloadSimpleProperty payloadProperty = new PayloadSimpleProperty(parent); payloadProperty.Name = xmlData.Name.LocalName; payloadProperty.Value = xmlData.Value; XAttribute nullAttribute = xmlData.Attribute(m + "null"); if (nullAttribute != null && nullAttribute.Value == "true") { payloadProperty.Value = null; payloadProperty.IsNull = true; } XAttribute typeAttribute = xmlData.Attribute(m + "type"); if (typeAttribute != null) payloadProperty.Type = typeAttribute.Value; return payloadProperty; }
internal PayloadSimpleProperty parseSimpleObject(PayloadObject parent, JSField field) { PayloadSimpleProperty payloadProperty = new PayloadSimpleProperty(parent); payloadProperty.Name = field.Name; object val = field.GetValue(field); if (val is System.DBNull) { payloadProperty.Value = null; payloadProperty.Type = null; payloadProperty.IsNull = true; } else { payloadProperty.Type = AstoriaUnitTests.Data.TypeData.FindForType(val.GetType()).GetEdmTypeName(); payloadProperty.Value = ConvertJsonValue(val); payloadProperty.IsNull = false; } return payloadProperty; }
internal PayloadComplexProperty ParseComplexProperty(PayloadObject parent, XElement xmlData) { PayloadComplexProperty payloadProperty = new PayloadComplexProperty(parent); payloadProperty.Name = xmlData.Name.LocalName; XAttribute nullAttribute = xmlData.Attribute(m + "null"); if (nullAttribute != null && nullAttribute.Value == "true") payloadProperty.IsNull = true; XAttribute typeAttribute = xmlData.Attribute(m + "type"); if (typeAttribute != null) payloadProperty.Type = typeAttribute.Value; foreach (XElement property in xmlData.Elements()) { PayloadProperty subProperty; if (property.HasElements) { subProperty = ParseComplexProperty(parent, property); } else { subProperty = ParseSimpleProperty(parent, property); } payloadProperty.PayloadProperties.Add(subProperty.Name, subProperty); } return payloadProperty; }
// DO NOT INSTANTIATE THIS DIRECTLY. Use either CommonPayload.CreateCommonPayload or AstoriaResponse.CommonPayload internal JSONPayload(AstoriaRequestResponseBase rr) : base(rr) { string jsonString = this.RawPayload; if (jsonString == null) { this.Value = null; return; } jsonString = StripSecurityWrapper(jsonString); object jsonData = null; try { jsonData = Evaluator.EvalToObject("(" + jsonString + ")"); } catch (Exception e) { this.Value = jsonString; return; } if (jsonData is ArrayObject) { this.Resources = ParseJsonArray((ArrayObject)jsonData); } else if (jsonData is JSObject) { FieldInfo[] fields = ((JSObject)jsonData).GetFields(BindingFlags.Default); // v2-style array, with count/page if (fields.Any(field => field.Name == v2JsonResultsField)) { foreach (FieldInfo field in fields) { object value = field.GetValue(field); switch (field.Name) { case v2NextField: this.NextLink = value.ToString(); break; case v2CountField: this.Count = Convert.ToInt64(value.ToString()); break; case v2JsonResultsField: if (value is ArrayObject) this.Resources = ParseJsonArray((ArrayObject)value); else AstoriaTestLog.FailAndThrow("Array expected in results field"); break; default: AstoriaTestLog.FailAndThrow("Field '" + field.Name + "' unexpected"); break; } } } else if (fields.Any(field => field.Name == "__metadata")) { this.Resources = ParseSingleJsonObject((JSObject)jsonData); // entry } else { if (fields.Length > 1) AstoriaTestLog.FailAndThrow("Single field expected for non-entry payload"); FieldInfo field = fields[0]; object value = field.GetValue(field); PayloadObject payloadObject = new PayloadObject(this); PayloadProperty property; if (value is JSObject) property = parseComplexObject(payloadObject, (JSField)field); else property = parseSimpleObject(payloadObject, (JSField)field); if (property.Name != "uri") this.Resources = property; else { // this is to match the resulting structure for parsing links in ATOM / json collections PayloadObject temp = new PayloadObject(this); temp.Name = property.Name; temp.PayloadProperties.Add(property); this.Resources = new List<PayloadObject>() { temp }; } } } else { this.Value = jsonString; // must be $value } }
public PayloadProperty(PayloadObject parent) { this.ParentObject = parent; this.MappedOutOfContent = false; //by default, assume not }
private void VerifyProperties(ResourceType type, PayloadObject inserted, PayloadObject returned, bool missingInsertPropertiesOk, Func <ResourceProperty, bool> strictEquality) { List <string> propertyNames = inserted.PayloadProperties.Union(returned.PayloadProperties).Select(p => p.Name).ToList(); propertyNames.AddRange(inserted.CustomEpmMappedProperties.Keys); propertyNames.AddRange(returned.CustomEpmMappedProperties.Keys); foreach (string propertyName in propertyNames.Distinct()) { PayloadProperty insertedProperty; if (inserted.Format == SerializationFormatKind.JSON) //in JSON the first one wins { insertedProperty = inserted.PayloadProperties.FirstOrDefault(p => p.Name == propertyName); } else //in xml the last one wins { insertedProperty = inserted.PayloadProperties.LastOrDefault(p => p.Name == propertyName); } bool insertHadProperty = insertedProperty != null; PayloadProperty returnedProperty = returned.PayloadProperties.LastOrDefault(p => p.Name == propertyName);; bool returnedHadProperty = returnedProperty != null; ResourceProperty property = type.Properties.OfType <ResourceProperty>().SingleOrDefault(p => p.Name == propertyName); if (property == null || !property.Facets.IsDeclaredProperty) { if (!type.Facets.IsOpenType) { string error = "included dynamic property '" + propertyName + "' despite '" + type.Name + "' not being an open type"; if (insertHadProperty && returnedHadProperty) { AstoriaTestLog.FailAndThrow("Both the inserted and returned objects " + error); } else if (insertHadProperty) { AstoriaTestLog.FailAndThrow("The inserted object " + error); } else if (returnedHadProperty) { AstoriaTestLog.FailAndThrow("The returned object " + error); } } else { if (insertHadProperty && returnedHadProperty) { CompareDynamicPropertyValues(insertedProperty, returnedProperty); } else if (insertHadProperty) { // only acceptable if inserted value was null if (insertedProperty.IsNull) { AstoriaTestLog.FailAndThrow("Returned object missing non-null dynamic property '" + propertyName + "'"); } } } } else { if (property.IsNavigation) { // the insert payload may not specify this property //PayloadObject insertedObject = inserted.PayloadObjects.SingleOrDefault(o => o.Name == property.Name); PayloadObject returnedObject = returned.PayloadObjects.Single(o => o.Name == property.Name); // returned thing should be deferred whether its a reference or not AstoriaTestLog.AreEqual(true, returnedObject.Deferred, "!returnedObject.Deferred", false); // TODO: verify only expected links are present (based on uri and payload values as well) } else { if (insertHadProperty && returnedHadProperty) { try { ComparePropertyValues(property, insertedProperty, returnedProperty, strictEquality(property)); } catch (Exception e) { throw new TestFailedException("Value of property '" + property.Name + "' does not match inserted value", null, null, e); } } else if (insertHadProperty) { AstoriaTestLog.FailAndThrow("Returned object unexpectedly missing declared property '" + propertyName + "'"); } else if (returnedHadProperty) { if (missingInsertPropertiesOk) { AstoriaTestLog.WriteLineIgnore("Ignoring missing declared property '" + propertyName + "' in insert payload"); } else { AstoriaTestLog.FailAndThrow("Inserted object unexpectedly missing declared property '" + propertyName + "'"); } } } } } }
internal static KeyedResourceInstance CreateKeyedResourceInstanceFromPayloadObject(ResourceContainer container, ResourceType resourceType, PayloadObject payloadObject) { List<ResourceInstanceProperty> properties = new List<ResourceInstanceProperty>(); List<ResourceInstanceProperty> keyProperties = new List<ResourceInstanceProperty>(); foreach (ResourceProperty property in resourceType.Properties.OfType<ResourceProperty>()) { if (property.IsNavigation) continue; if (property.IsComplexType) { PayloadComplexProperty fromPayload = payloadObject[property.Name] as PayloadComplexProperty; properties.Add(ConvertComplexPayloadObjectToComplexProperty(property, fromPayload)); } else { string stringValue; if (payloadObject.PayloadProperties.Any(p => p.Name == property.Name)) { PayloadSimpleProperty fromPayload = payloadObject[property.Name] as PayloadSimpleProperty; stringValue = fromPayload.Value; } else { if (!payloadObject.CustomEpmMappedProperties.TryGetValue(property.Name, out stringValue)) stringValue = null; } ResourceInstanceProperty newProperty = null; object val = CommonPayload.DeserializeStringToObject(stringValue, property.Type.ClrType, false, payloadObject.Format); newProperty = new ResourceInstanceSimpleProperty(property.Name, new NodeValue(val, property.Type)); if (property.PrimaryKey != null) keyProperties.Add(newProperty); else properties.Add(newProperty); } } ResourceInstanceKey key = new ResourceInstanceKey(container, resourceType, keyProperties.ToArray()); return new KeyedResourceInstance(key, properties.ToArray()); }
public PayloadComplexProperty(PayloadObject parent) : base(parent) { PayloadProperties = new Dictionary<string, PayloadProperty>(); }
public PayloadComplexProperty(PayloadObject parent) : base(parent) { PayloadProperties = new Dictionary <string, PayloadProperty>(); }
internal PayloadObject ParseUriNode(XElement node) { PayloadObject po = new PayloadObject(this); PayloadSimpleProperty property = new PayloadSimpleProperty(po); property.Value = node.Value; property.Name = node.Name.LocalName; po.Name = node.Name.LocalName; po.PayloadProperties.Add(property); return po; }
internal PayloadObject ParseEntry(XElement xmlData) { PayloadObject payloadObject = new PayloadObject(this); #region edit link XElement linkEdit = xmlData.Elements(atom + "link").SingleOrDefault(l => l.Attribute("rel") != null && l.Attribute("rel").Value == "edit"); if (linkEdit != null) payloadObject.Uri = linkEdit.Attribute("href").Value; #endregion #region id link XElement idNode = xmlData.Element(atom + "id"); if (idNode != null) payloadObject.Uri = idNode.Value; // TODO: compare the edit link to the ID node's value #endregion #region name XElement titleNode = xmlData.Parent; if (titleNode != null && titleNode.Name == m + "inline") { XAttribute titleAttribute = titleNode.Parent.Attribute("title"); if (titleAttribute != null) payloadObject.Name = titleAttribute.Value; } else if (titleNode != null) { titleNode = titleNode.Element(atom + "title"); if (titleNode != null) payloadObject.Name = titleNode.Value; } else if (linkEdit != null) { XAttribute titleAttribute = linkEdit.Attribute("title"); if (titleAttribute != null) payloadObject.Name = titleAttribute.Value; } #endregion #region type bool isMediaLink = false; XElement category = xmlData.Element(atom + "category"); ResourceType type = null; if (category != null) { XAttribute term = category.Attribute("term"); if (term != null) { payloadObject.Type = term.Value; type = Workspace.ServiceContainer.ResourceTypes.Single(rt => rt.Namespace + "." + rt.Name == term.Value); if (type.Facets.HasStream) isMediaLink = true; } } #endregion #region friendly feeds ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty.Title, xmlData, payloadObject); ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty.Summary, xmlData, payloadObject); ParseNullableSyndicationItemProperty(AtomSyndicationItemProperty.Rights, xmlData, payloadObject); //This is the correct mapping for Friendly Feeds SyndicationItemProperty.Published XElement ffEntryPublishedNode = xmlData.Element(atom + "published"); if (ffEntryPublishedNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.Published] = ffEntryPublishedNode.Value; //This is the correct mapping for Friendly Feeds SyndicationItemProperty.Updated XElement ffEntryUpdatedNode = xmlData.Element(atom + "updated"); if (ffEntryUpdatedNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.Updated] = ffEntryUpdatedNode.Value; //This is the correct mapping for Friendly Feeds Author Node XElement ffEntryAuthorNode = xmlData.Element(atom + "author"); if (ffEntryAuthorNode != null) { //Friendly Feeds SyndicationItemProperty.AuthorEmail XElement ffEmailNode = ffEntryAuthorNode.Element(atom + "email"); if (ffEmailNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.AuthorEmail] = ffEmailNode.Value; //Friendly Feeds SyndicationItemProperty.AuthorName XElement ffNameNode = ffEntryAuthorNode.Element(atom + "name"); if (ffNameNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.AuthorName] = ffNameNode.Value; //Friendly Feeds SyndicationItemProperty.AuthorUri XElement ffUriNode = ffEntryAuthorNode.Element(atom + "uri"); if (ffUriNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.AuthorUri] = ffUriNode.Value; } //This is the correct mapping for Friendly Feeds Contributor Node XElement ffEntryContributorNode = xmlData.Element(atom + "contributor"); if (ffEntryContributorNode != null) { //Friendly Feeds SyndicationItemProperty.ContributorEmail XElement ffEmailNode = ffEntryContributorNode.Element(atom + "email"); if (ffEmailNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.ContributorEmail] = ffEmailNode.Value; //Friendly Feeds SyndicationItemProperty.ContributorName XElement ffNameNode = ffEntryContributorNode.Element(atom + "name"); if (ffNameNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.ContributorName] = ffNameNode.Value; //Friendly Feeds SyndicationItemProperty.ContributorUri XElement ffUriNode = ffEntryContributorNode.Element(atom + "uri"); if (ffUriNode != null) payloadObject.SyndicationItemProperties[AtomSyndicationItemProperty.ContributorUri] = ffUriNode.Value; } #endregion #region etag if (xmlData.HasAttributes) { XAttribute etagNodeAttribute = xmlData.Attribute(m + "etag"); if (etagNodeAttribute != null) payloadObject.ETag = etagNodeAttribute.Value; } #endregion #region properties XElement content = xmlData.Element(atom + "content"); XElement properties = null; if (content != null) { XAttribute contentType = content.Attribute("type"); if (contentType != null) { if (!isMediaLink) { StringComparison comp; if (WasResponse) comp = StringComparison.InvariantCulture; else comp = StringComparison.InvariantCultureIgnoreCase; if (!contentType.Value.Equals("application/xml", comp)) AstoriaTestLog.AreEqual("application/xml", contentType.Value, "Unexpected type on content element", true); properties = content.Element(m + "properties"); } // TODO: save content type if its a media link } } if (isMediaLink) properties = xmlData.Element(m + "properties"); if (properties != null) { foreach (XElement element in properties.Elements()) { PayloadProperty property; if (element.HasElements) { property = ParseComplexProperty(payloadObject, element); } else { property = ParseSimpleProperty(payloadObject, element); } payloadObject.PayloadProperties.Add(property); } } #endregion #region links foreach (XElement link in xmlData.Elements(atom + "link")) { Uri linkRel = new Uri(link.Attribute("rel").Value, UriKind.RelativeOrAbsolute); if (linkRel.IsAbsoluteUri) { string linkRelValue = linkRel.GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); if (linkRelValue.StartsWith(DataWebRelatedNamespace, StringComparison.Ordinal)) { XElement inlineTag = link.Element(m + "inline"); if (inlineTag != null) { PayloadObject nestedPayloadObject = new PayloadObject(this); nestedPayloadObject.Name = linkRelValue.Substring(DataWebRelatedNamespace.Length); string linkType = link.Attribute("type").Value; if (linkType.Contains("feed")) { if (inlineTag.HasElements) nestedPayloadObject.PayloadObjects.AddRange(this.ParseFeed(inlineTag.Elements().Single())); } else if (linkType.Contains("entry")) { if (inlineTag.HasElements) nestedPayloadObject = this.ParseEntry(inlineTag.Elements().Single()); nestedPayloadObject.Reference = true; } payloadObject.PayloadObjects.Add(nestedPayloadObject); } else { // deferred links PayloadObject deferredObject = new PayloadObject(this); deferredObject.Name = linkRelValue.Substring(DataWebRelatedNamespace.Length); if (link.Attribute("href") != null) deferredObject.Uri = link.Attribute("href").Value; deferredObject.Deferred = true; payloadObject.PayloadObjects.Add(deferredObject); } } else if (linkRelValue.StartsWith(DataWebMediaResourceNamespace)) { string name = linkRelValue.Substring(DataWebMediaResourceNamespace.Length); PayloadNamedStream namedStream = payloadObject.NamedStreams.SingleOrDefault(s => s.Name == name); if (namedStream == null) { namedStream = new PayloadNamedStream() { Name = name }; payloadObject.NamedStreams.Add(namedStream); } UpdateNamedStreamMetadata(link, namedStream); namedStream.SelfLink = link.Attribute("href").Value; } else if (linkRelValue.StartsWith(DataWebMediaResourceEditNamespace)) { string name = linkRelValue.Substring(DataWebMediaResourceEditNamespace.Length); PayloadNamedStream namedStream = payloadObject.NamedStreams.SingleOrDefault(s => s.Name == name); if (namedStream == null) { namedStream = new PayloadNamedStream() { Name = name }; payloadObject.NamedStreams.Add(namedStream); } UpdateNamedStreamMetadata(link, namedStream); namedStream.EditLink = link.Attribute("href").Value; } } } #endregion return payloadObject; }
private void Verify(AstoriaRequest request) { RequestVerb verb = request.EffectiveVerb; bool merge = verb == RequestVerb.Patch; PayloadObject entityBefore; if (!TryGetSingleObjectFromPayload(request.BeforeUpdatePayload, out entityBefore)) { AstoriaTestLog.FailAndThrow("Pre-update payload did not contain a single entity"); } // determine the type based on what was there (doing .Single() doesn't work for MEST, because the type shows up twice) ResourceType type = request.Workspace.ServiceContainer.ResourceTypes.First(rt => entityBefore.Type.Equals(rt.Namespace + "." + rt.Name)); PayloadObject entityAfter; if (!TryGetSingleObjectFromPayload(request.AfterUpdatePayload, out entityAfter)) { AstoriaTestLog.FailAndThrow("Post-update payload did not contain a single entity"); } CommonPayload updatePayload = request.CommonPayload; PayloadObject entityUpdate = null; if (request.URI.EndsWith("$value")) { Match match = Regex.Match(request.URI, @".*/(.+)/\$value"); if (!match.Success) { AstoriaTestLog.FailAndThrow("Could not determine property name for $value request"); } string propertyValue = null; if (request.ContentType.Equals(SerializationFormatKinds.MimeApplicationOctetStream, StringComparison.InvariantCultureIgnoreCase)) { object value = (request.UpdateTree as ResourceInstanceSimpleProperty).PropertyValue; if (updatePayload.Format == SerializationFormatKind.JSON) { propertyValue = JSONPayload.ConvertJsonValue(value); } else { AstoriaTestLog.FailAndThrow("Unsure how to fake property value"); } } else { propertyValue = request.Payload; } entityUpdate = new PayloadObject(updatePayload); PayloadSimpleProperty propertyUpdate = new PayloadSimpleProperty(entityUpdate); propertyUpdate.Name = match.Groups[1].Value; propertyUpdate.Value = propertyValue; entityUpdate.PayloadProperties.Add(propertyUpdate); merge = true; //PUT to a single property doesn't reset the resource } else if (!TryGetSingleObjectFromPayload(updatePayload, out entityUpdate)) { // must be a single property update PayloadProperty propertyUpdate = updatePayload.Resources as PayloadProperty; if (propertyUpdate == null) { AstoriaTestLog.FailAndThrow("Expected either a property or an entity in the update payload"); } entityUpdate = new PayloadObject(updatePayload); entityUpdate.PayloadProperties.Add(propertyUpdate); propertyUpdate.ParentObject = entityUpdate; merge = true; //PUT to a single property doesn't reset the resource } List <string> allPropertyNames = entityBefore.PayloadProperties .Union(entityAfter.PayloadProperties) .Union(entityUpdate.PayloadProperties) .Select(p => p.Name) .ToList(); allPropertyNames.AddRange(entityBefore.CustomEpmMappedProperties.Keys); allPropertyNames.AddRange(entityUpdate.CustomEpmMappedProperties.Keys); allPropertyNames.AddRange(entityAfter.CustomEpmMappedProperties.Keys); foreach (string propertyName in allPropertyNames.Distinct()) { PayloadProperty original = null; bool originalHadProperty = entityBefore.PayloadProperties.Any(p => (original = p).Name == propertyName); PayloadProperty update = null; bool updateHadProperty = entityUpdate.PayloadProperties.Any(p => (update = p).Name == propertyName); PayloadProperty final = null; bool finalHadProperty = entityAfter.PayloadProperties.Any(p => (final = p).Name == propertyName); if (type.Properties.Any(p => p.Name == propertyName && p.Facets.IsDeclaredProperty)) { // declared property if (!finalHadProperty) { AstoriaTestLog.FailAndThrow("Final version of entity is missing declared property '" + propertyName + "'"); } ResourceProperty property = type.Properties[propertyName] as ResourceProperty; if (property.IsNavigation) { continue; } if (!originalHadProperty) { AstoriaTestLog.FailAndThrow("Original version of entity is missing declared property '" + propertyName + "'"); } bool checkValue = property.PrimaryKey == null && !property.Facets.ServerGenerated; // if we changed it, we don't care what it was if (updateHadProperty) { ComparePropertyValues(property, update, final, checkValue); } else if (merge) { ComparePropertyValues(property, original, final, checkValue); } else if (checkValue) { CompareResetProperty(property, final); } } else { // dynamic property if (updateHadProperty) { if (!finalHadProperty) { AstoriaTestLog.FailAndThrow("Final version of entity is missing dynamic property '" + propertyName + "'"); } CompareDynamicPropertyValues(update, final); } else if (merge) { if (!finalHadProperty) { AstoriaTestLog.FailAndThrow("Final version of entity is missing dynamic property '" + propertyName + "'"); } CompareDynamicPropertyValues(original, final); } else if (finalHadProperty) { AstoriaTestLog.FailAndThrow("Dynamic property '" + propertyName + "' was not cleared after reset"); } } } }