예제 #1
0
        /// <summary>
        /// Implements IDataInserter.AddEntity by creating a POST-based insert request and adding it to the batch queue
        /// </summary>
        /// <param name="key">Key expression for new entity</param>
        /// <param name="entity">Update tree for new entity</param>
        public void AddEntity(KeyExpression key, KeyedResourceInstance entity)
        {
            // build the request
            //
            ExpNode        containerQuery = ContainmentUtil.BuildCanonicalQuery(key, true);
            AstoriaRequest request        = workspace.CreateRequest(containerQuery, entity, RequestVerb.Post);

            // set ETagHeaderExpected appropriately
            if (key.ResourceType.Properties.Any(p => p.Facets.ConcurrencyModeFixed))
            {
                request.ETagHeaderExpected = true;
            }

            // add it to the queue
            //
            queue.Add(request);

            // store the content-id
            //
            contentIDMap[entity] = request.Headers["Content-ID"];

            // fire the event
            //
            if (this.OnAddingEntity != null)
            {
                OnAddingEntity(key, entity);
            }
        }
예제 #2
0
        //---------------------------------------------------------------------
        // Constructs AstoriaRequest and sets.
        //---------------------------------------------------------------------
        private BlobsRequest(Workspace w, SerializationFormatKind format, RequestVerb verb, string uri, HttpStatusCode expectedStatusCode) : base(w)
        {
            // Common settings for MLEs and MRs.
            base.IsBlobRequest      = true;
            base.Verb               = verb;
            base.ExpectedStatusCode = expectedStatusCode;

            // Construct request URI.
            if (uri.Contains("(*)"))
            {
                // Replace (*) with random key.
                string            relativeURI = uri.Remove(0, w.ServiceUri.Length + 1);
                ResourceContainer container   = w.ServiceContainer.ResourceContainers[relativeURI.Substring(0, relativeURI.IndexOf("(*)"))];
                KeyExpression     key         = null;
                try { key = w.GetRandomExistingKey(container, container.BaseType); } catch (Exception e) { AstoriaTestLog.Skip("Unable to get random key"); }
                base.Query = ContainmentUtil.BuildCanonicalQuery(key);
                base.URI  += relativeURI.Substring(relativeURI.IndexOf("(*)") + 3);
            }
            else
            {
                // Deterministic URI.
                base.URI = uri;
            }

            LastURI = base.URI;
        }
예제 #3
0
        public static AstoriaRequest BuildGet(Workspace workspace, KeyExpression key, HttpStatusCode expectedStatusCode, SerializationFormatKind format)
        {
            QueryNode query = ContainmentUtil.BuildCanonicalQuery(key);

            string keyString = UriQueryBuilder.CreateKeyString(key, false);

            if ((expectedStatusCode == System.Net.HttpStatusCode.OK) && (keyString.Contains("/") || keyString.Contains(Uri.EscapeDataString("/"))))
            {
                expectedStatusCode = System.Net.HttpStatusCode.BadRequest;
            }

            return(BuildGet(workspace, query, expectedStatusCode, format));
        }
예제 #4
0
        public static AstoriaRequest BuildInsert(Workspace workspace, ResourceContainer container, ResourceType type,
                                                 HttpStatusCode expectedStatusCode, SerializationFormatKind format, out KeyExpression createdKey)
        {
            KeyedResourceInstance newResource = type.CreateRandomResource(container);

            if (newResource == null)
            {
                newResource = ResourceInstanceUtil.CreateKeyedResourceInstanceByClone(container, type);

                if (newResource == null)
                {
                    createdKey = null;
                    return(null);
                }
            }

            QueryNode query;

            if (!type.Key.Properties.Any(p => p.Facets.ServerGenerated) && newResource.ResourceInstanceKey != null)
            {
                createdKey = newResource.ResourceInstanceKey.CreateKeyExpression(container, type);
                query      = ContainmentUtil.BuildCanonicalQuery(createdKey, true);
            }
            else
            {
                createdKey = null;
                // the key is unknown, must be server generated
                // in this case, lets hope that containment is a non-issue
                query =
                    Query.From(Exp.Variable(container))
                    .Select();
                if (!container.Facets.TopLevelAccess && expectedStatusCode == HttpStatusCode.Created)
                {
                    expectedStatusCode = HttpStatusCode.BadRequest;
                }
            }

            AstoriaRequest request = workspace.CreateRequest();

            request.Verb               = RequestVerb.Post;
            request.Query              = query;
            request.UpdateTree         = newResource;
            request.ExpectedStatusCode = expectedStatusCode;
            request.Format             = format;

            return(request);
        }
예제 #5
0
        public static AstoriaRequest BuildDelete(Workspace workspace, KeyExpression toDelete, HttpStatusCode expectedStatusCode, SerializationFormatKind format)
        {
            QueryNode query = ContainmentUtil.BuildCanonicalQuery(toDelete);

            AstoriaRequest request = workspace.CreateRequest();

            request.Verb               = RequestVerb.Delete;
            request.Query              = query;
            request.Format             = format;
            request.ExpectedStatusCode = expectedStatusCode;

            if (toDelete.ResourceType.Properties.Any(p => p.Facets.ConcurrencyModeFixed))
            {
                request.Headers[ConcurrencyUtil.IfMatchHeader] = toDelete.ETag;
            }

            return(request);
        }
예제 #6
0
        protected string CreateCanonicalUri(ResourceInstanceKey key)
        {
            UriQueryBuilder builder = new UriQueryBuilder(Workspace, Workspace.ServiceUri);

            builder.UseBinaryFormatForDates  = false;
            builder.CleanUpSpecialCharacters = false;

            KeyExpression keyExpression = ResourceInstanceUtil.ConvertToKeyExpression(key, Workspace);

            if (keyExpression != null)
            {
                QueryNode query = ContainmentUtil.BuildCanonicalQuery(keyExpression);
                return(builder.Build(query));
            }

            IEnumerable <ResourceInstanceSimpleProperty> properties = key.KeyProperties.OfType <ResourceInstanceSimpleProperty>();

            string keyString = builder.CreateKeyString(properties.Select(p => p.Name).ToArray(), properties.Select(p => p.PropertyValue).ToArray());
            string uri       = Workspace.ServiceUri + "/" + key.ResourceSetName + "(" + keyString + ")";

            return(uri);
        }
예제 #7
0
        public static AstoriaRequest BuildUpdate(Workspace workspace, KeyExpression modifiedKey, bool replace, HttpStatusCode expectedStatusCode, SerializationFormatKind format)
        {
            if (modifiedKey == null)
            {
                return(null);
            }

            ResourceContainer container    = modifiedKey.ResourceContainer;
            ResourceType      resourceType = modifiedKey.ResourceType;

            if (replace && resourceType.Properties.Any(p => p.Facets.IsIdentity))
            {
                return(null);
            }

            string keyString = UriQueryBuilder.CreateKeyString(modifiedKey, false);

            if (expectedStatusCode == HttpStatusCode.NoContent && (keyString.Contains("/") || keyString.Contains(Uri.EscapeDataString("/"))))
            {
                expectedStatusCode = HttpStatusCode.BadRequest;
            }

            QueryNode query = ContainmentUtil.BuildCanonicalQuery(modifiedKey);

            List <ResourceInstanceProperty> properties = new List <ResourceInstanceProperty>();

            string[] propertiesToSkip;
            //Skip because setting the birthdate to a random Datetime won't work due to contraints
            //if (resourceType.Name == "Employees")
            //    propertiesToSkip = new string[] { "BirthDate" };
            ////Skipping because it has some weird constraint on it
            //else if (resourceType.Name == "Order_Details")
            //    propertiesToSkip = new string[] { "Discount" };
            //else
            //    propertiesToSkip = new string[] { };

            foreach (ResourceProperty resourceProperty in resourceType.Properties.OfType <ResourceProperty>()
                     .Where(p => !p.IsNavigation &&
                            p.PrimaryKey == null &&
                            !p.Facets.IsIdentity))
            //&& !p.IsComplexType
            //&& !propertiesToSkip.Contains(p.Name)))
            {
                properties.Add(resourceProperty.CreateRandomResourceInstanceProperty());
            }

            if (!properties.Any())
            {
                return(null);
            }

            KeyedResourceInstance resourceInstance = new KeyedResourceInstance(
                ResourceInstanceKey.ConstructResourceInstanceKey(modifiedKey),
                properties.ToArray());

            AstoriaRequest request = workspace.CreateRequest();

            request.Verb               = replace ? RequestVerb.Put : RequestVerb.Patch;
            request.Query              = query;
            request.UpdateTree         = resourceInstance;
            request.ExpectedStatusCode = expectedStatusCode;
            request.Format             = format;

            if (modifiedKey.ResourceType.Properties.Any(p => p.Facets.ConcurrencyModeFixed))
            {
                request.Headers[ConcurrencyUtil.IfMatchHeader] = modifiedKey.ETag;
                request.ETagHeaderExpected = true;
            }

            return(request);
        }
예제 #8
0
        protected override void Verify()
        {
            if (!Applies(Response))
            {
                return;
            }

            // build a common payload for the insert
            //
            CommonPayload insertPayload = Response.Request.CommonPayload;

            // get the entity that was inserted
            PayloadObject inserted;

            if (!TryGetSingleObjectFromPayload(insertPayload, out inserted))
            {
                ResponseVerification.LogFailure(Response, new Exception("Insert request payload did not contain a single entity"));
            }

            // determine the type based on what was inserted
            ResourceType type = Response.Workspace.ServiceContainer.ResourceTypes.Single(rt => inserted.Type.Equals(rt.Namespace + "." + rt.Name));

            // get the entity that was returned
            PayloadObject returned;

            if (!TryGetSingleObjectFromPayload(Response.CommonPayload, out returned))
            {
                if (Versioning.Server.SupportsLiveFeatures)
                {
                    string preferHeader;
                    if (Response.Request.Headers.TryGetValue("prefer", out preferHeader) && preferHeader == "return=minimal")
                    {
                        return;
                    }
                }

                ResponseVerification.LogFailure(Response, new Exception("Insert response payload did not contain a single entity"));
            }

            // verify that the inserted and returned entities are equivalent
            VerifyInsertResponse(type, inserted, returned);

            // re-query the entity
            Workspace      workspace    = Response.Workspace;
            AstoriaRequest queryRequest = workspace.CreateRequest();

            if (type.Properties.Any(p => p.Facets.ConcurrencyModeFixed))
            {
                queryRequest.ETagHeaderExpected = true;
            }

            if (type.Key.Properties.Any(p => p.Type == Clr.Types.DateTime))
            {
                // this will blow up for MEST, but we don't currently have any datetime key + MEST types
                ResourceContainer container = Response.Workspace.ServiceContainer.ResourceContainers.Single(rc => !(rc is ServiceOperation) && rc.ResourceTypes.Contains(type));
                queryRequest.Query = ContainmentUtil.BuildCanonicalQuery(ConcurrencyUtil.ConstructKey(container, returned));
            }
            else
            {
                queryRequest.URI = Uri.UnescapeDataString(returned.AbsoluteUri);
                if (queryRequest.URI.Contains("E+"))
                {
                    queryRequest.URI = queryRequest.URI.Replace("E+", "E");
                }
                if (queryRequest.URI.Contains("e+"))
                {
                    queryRequest.URI = queryRequest.URI.Replace("e+", "e");
                }
            }

            AstoriaResponse queryResponse = queryRequest.GetResponse();

            if (queryResponse.ActualStatusCode == HttpStatusCode.BadRequest)
            {
                // try it as a filter instead (possibly caused by the URI being too long)
                // this will blow up for MEST
                ResourceContainer container = Response.Workspace.ServiceContainer.ResourceContainers
                                              .Single(rc => !(rc is ServiceOperation) && rc.ResourceTypes.Contains(type));
                KeyExpression key = ConcurrencyUtil.ConstructKey(container, returned);
                queryRequest  = workspace.CreateRequest(Query.From(Exp.Variable(container)).Where(key.Predicate));
                queryResponse = queryRequest.GetResponse();
            }
            queryResponse.Verify();

            // get the entity from the query
            PayloadObject queried;

            if (!TryGetSingleObjectFromPayload(queryResponse.CommonPayload, out queried))
            {
                ResponseVerification.LogFailure(queryResponse, new Exception("Query response payload did not contain a single entity"));
            }

            // ensure that the entity did not change between the insert and the re-query
            VerifyQueryResponse(type, returned, queried);
        }
예제 #9
0
        private static bool compareKeyURI(string uriFound, KeyExpression keyExpected)
        {
            UriQueryBuilder builder = new UriQueryBuilder(keyExpected.ResourceContainer.Workspace, keyExpected.ResourceContainer.Workspace.ServiceUri);

            builder.EscapeUriValues          = true;
            builder.CleanUpSpecialCharacters = false;
            builder.UseBinaryFormatForDates  = false;

            switch (keyExpected.IncludeInUri.Count(i => i))
            {
            case 0:
                AstoriaTestLog.FailAndThrow("Cannot compare KeyExpression to URI, key has no included values");
                return(false);

            case 1:
                // TODO: stop ignoring case
                QueryNode query    = ContainmentUtil.BuildCanonicalQuery(keyExpected);
                string    expected = builder.Build(query);

                expected = expected.Replace(".0f", "f");     //this is kinda a hack, but TypeData.FormatForKey is going to add the .0, so we need to remove it
                expected = expected.Replace(".0D", "D");     //this is kinda a hack, but TypeData.FormatForKey is going to add the .0, so we need to remove it
                bool match = uriFound.Equals(expected, StringComparison.InvariantCultureIgnoreCase);
                if (!match)
                {
                    AstoriaTestLog.WriteLineIgnore("Link did not match key, expected '" + expected + "'");
                }
                return(match);

            default:
                QueryNode setQuery = ContainmentUtil.BuildCanonicalQuery(keyExpected, true);

                Workspace w      = keyExpected.ResourceContainer.Workspace;
                string    setUri = builder.Build(setQuery);

                string keySegment = uriFound.Substring(setUri.Length);

                string expectedKeySegment = "(" + UriQueryBuilder.CreateKeyString(keyExpected, false) + ")";

                if (keySegment.Equals(expectedKeySegment, StringComparison.InvariantCultureIgnoreCase))
                {
                    return(true);
                }

                // if not explicitely equal, need to make sure its not due to a re-ordering of the properties
                //
                List <KeyValuePair <string, int> > predicateLocations = new List <KeyValuePair <string, int> >();
                for (int i = 0; i < keyExpected.Values.Length; i++)
                {
                    string predicate = builder.CreateKeyStringPair(keyExpected.Properties[i].Name, keyExpected.Values[i].ClrValue);
                    int    offset    = keySegment.IndexOf(predicate);
                    if (offset < 0)
                    {
                        return(false);
                    }

                    predicateLocations.Add(new KeyValuePair <string, int>(predicate, offset));
                }

                predicateLocations.Sort(delegate(KeyValuePair <string, int> pair1, KeyValuePair <string, int> pair2)
                {
                    return(pair1.Value.CompareTo(pair2.Value));
                });

                expectedKeySegment = "(" + String.Join(",", predicateLocations.Select(pair => pair.Key).ToArray()) + ")";

                return(keySegment.Equals(expectedKeySegment, StringComparison.InvariantCultureIgnoreCase));
            }
        }