Exemple #1
0
        /// <summary>
        /// Verifies the descriptor after execute.
        /// </summary>
        /// <param name="continuation">The continuation.</param>
        /// <param name="dataContext">The data context.</param>
        /// <param name="entityPayloads">The list of entities</param>
        /// <param name="expectedValue">The expected value.</param>
        protected void VerifyDescriptorAfterExecute(IAsyncContinuation continuation, DataServiceContext dataContext, IEnumerable <object> entityPayloads, QueryValue expectedValue)
        {
            // If no streams were generated as part of the test initialization then this block of verification is needed
            if (this.SkipGenerateNamedStream)
            {
                continuation.Continue();
            }
            else
            {
                object[] entities = entityPayloads.ToArray();
                if (this.DataProviderSettings.UsePayloadDrivenVerification)
                {
                    expectedValue = this.baselineQueryValue;
                }

                var expectedEntities = expectedValue as QueryCollectionValue;
                QueryStructuralValue element;

                if (expectedEntities == null)
                {
                    continuation.Continue();
                }
                else
                {
                    AsyncHelpers.AsyncForEach(
                        expectedEntities.Elements.ToList(),
                        continuation,
                        (qv, entityContinuation) =>
                    {
                        // NOTE: The results could be a list of AnonTypes at which point these wouldn't be have descriptors so
                        // no need to verify
                        element = qv as QueryStructuralValue;

                        var queryEntityType = element.Type as QueryEntityType;
                        if (queryEntityType == null)
                        {
                            entityContinuation.Continue();
                        }
                        else
                        {
                            var queryEntityValue        = element as QueryEntityValue;
                            QueryKeyStructuralValue key = queryEntityValue.Key();

                            // This handles the expand scenario (Orders(1)?$expand=Customer) where the entity in the list doesn't have a corresponding QueryStructuralValue
                            object entity = entities.Where(upe => queryEntityType.ClrType.IsAssignableFrom(upe.GetType()) && queryEntityType.GetEntityInstanceKey(upe).Equals(key)).FirstOrDefault();

                            if (entity == null)
                            {
                                entityContinuation.Continue();
                            }
                            else
                            {
                                EntityDescriptor ed  = dataContext.GetEntityDescriptor(entity);
                                var streamProperties = queryEntityType.Properties.Where(p => p.IsStream()).ToList();          // intentionally include the default stream
                                int expectedStreamDescriptorCount = streamProperties.Count(p => p.Name != AstoriaQueryStreamType.DefaultStreamPropertyName);
                                this.Assert.AreEqual(expectedStreamDescriptorCount, ed.StreamDescriptors.Count, "Entity descriptor had unexpected number of stream descriptors");

                                AsyncHelpers.AsyncForEach(
                                    streamProperties,
                                    entityContinuation,
                                    (streamProperty, streamDescriptorContinuation) =>
                                {
                                    if (streamProperty.Name == AstoriaQueryStreamType.DefaultStreamPropertyName)
                                    {
                                        this.VerifyDefaultStream(dataContext, element, ed, streamDescriptorContinuation);
                                    }
                                    else
                                    {
                                        this.VerifyNamedStreams(dataContext, element, streamProperty, ed, streamDescriptorContinuation);
                                    }
                                });
                            }
                        }
                    });
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Compares Collections, optimizes entity collection comparisons for better error messages or defers to the base
        /// </summary>
        /// <param name="expected">Expected Value</param>
        /// <param name="actualElements">Actual Elements to compare against</param>
        /// <param name="path">Path of the elements</param>
        /// <param name="shouldThrow">Should throw on error or not</param>
        /// <param name="comparisonSkippedForAnyElement">Skip for particular comparisons</param>
        /// <returns>A Comparison result</returns>
        protected override ComparisonResult CompareCollections(QueryCollectionValue expected, IEnumerable <object> actualElements, string path, bool shouldThrow, out bool comparisonSkippedForAnyElement)
        {
            comparisonSkippedForAnyElement = false;
            QueryEntityType queryEntityType = expected.Type.ElementType as QueryEntityType;

            if (queryEntityType != null)
            {
                List <QueryProperty> keyProperties = queryEntityType.Properties.Where(p => p.IsPrimaryKey).ToList();
                ExceptionUtilities.Assert(queryEntityType.Properties.Where(p => p.IsPrimaryKey).Count() > 0, "QueryEntityType '{0}' must have a Primary key defined in order to compare using primary keys", queryEntityType.EntityType.FullName);

                List <object> unprocessableElements = actualElements.Where(e => !queryEntityType.ClrType.IsAssignableFrom(e.GetType())).ToList();
                if (unprocessableElements.Count > 0)
                {
                    string errorDetails = string.Join(", ", unprocessableElements.Select(o => string.Format(CultureInfo.InvariantCulture, "Expected object '{0}' to be assignable to '{1}'", o.GetType().FullName, queryEntityType.ClrType.FullName)).ToArray());
                    this.ThrowOrLogError(shouldThrow, "There are '{0}' elements that are unprocessable, Details '{1}'", unprocessableElements.Count, errorDetails);
                    return(ComparisonResult.Failure);
                }

                List <object> unprocessedElements = actualElements.Where(e => queryEntityType.ClrType.IsAssignableFrom(e.GetType())).ToList();
                foreach (QueryStructuralValue queryStructuralValue in expected.Elements)
                {
                    var queryEntityValue = queryStructuralValue as QueryEntityValue;
                    ExceptionUtilities.CheckObjectNotNull(queryEntityValue, "Expected Collection element to be a 'QueryEntityValue', got a '{0}' instead", queryStructuralValue);
                    ExceptionUtilities.CheckObjectNotNull(queryEntityValue.IsNull, "Expected Collection of QueryEntityValues to not contain a QueryEntityValue that is null '{0}'", queryEntityValue.ToString());

                    // Note: We could fix this limitation by simply using the normal unsorted code path instead in these cases but no point implementing this unless its needed.
                    ExceptionUtilities.CheckObjectNotNull(keyProperties.Select(kp => queryEntityValue.GetScalarValue(kp.Name).IsNull).Any(), "Error: QueryEntityValue must have key values defined");

                    QueryKeyStructuralValue key = queryEntityValue.Key();
                    object entityInstance       = unprocessedElements.Where(upe => queryEntityType.GetEntityInstanceKey(upe).Equals(key)).SingleOrDefault();
                    if (entityInstance == null)
                    {
                        this.ThrowOrLogError(shouldThrow, "Cannot find actual EntityInstance that is assignable to type '{0}' with key '{1}' in expected collection '{2}'", queryEntityType.EntityType.FullName, key.GetDebugKeyString(), expected);
                        return(ComparisonResult.Failure);
                    }
                    else
                    {
                        unprocessedElements.Remove(entityInstance);
                        string           childPath   = string.Format(CultureInfo.InvariantCulture, "{0}.CollectionItem(ElementType='{1}',Key='{2}')", path, queryEntityType.EntityType.FullName, key.GetDebugKeyString());
                        ComparisonResult innerResult = this.Compare(queryEntityValue, entityInstance, childPath, false);

                        if (innerResult == ComparisonResult.Failure)
                        {
                            this.DisplayLog();
                            this.ThrowOrLogError(shouldThrow, "Comparision of EntityInstance in path '{0}' failed, see log for details", childPath, key.GetDebugKeyString(), expected);
                            return(ComparisonResult.Failure);
                        }
                    }
                }

                if (unprocessedElements.Count > 0)
                {
                    string errorDetails = string.Join(", ", unprocessedElements.Select(o => string.Format(CultureInfo.InvariantCulture, "Actual EntityInstance of type '{0}' with key '{1}' is not contained in expected collection '{2}'", o.GetType().FullName, queryEntityType.GetEntityInstanceKey(o).GetDebugKeyString(), expected)).ToArray());
                    this.ThrowOrLogError(shouldThrow, "There are '{0}' elements that are unprocessable, Details '{1}'", unprocessedElements.Count, errorDetails);
                    return(ComparisonResult.Failure);
                }

                return(ComparisonResult.Success);
            }
            else
            {
                return(base.CompareCollections(expected, actualElements, path, shouldThrow, out comparisonSkippedForAnyElement));
            }
        }