public void GetValue_Returns_SetValue() { // Arrange ETag etag = new ETag(); // Act & Assert etag["Name"] = "Name1"; Assert.Equal("Name1", etag["Name"]); }
public void DynamicGetValue_Returns_DynamicSetValue() { // Arrange dynamic etag = new ETag(); // Act & Assert etag.Name = "Name1"; Assert.Equal("Name1", etag.Name); }
public void GetValue_ThrowsInvalidOperation_IfNotWellFormed() { // Arrange ETag etag = new ETag(); etag["Name"] = "Name1"; etag.IsWellFormed = false; // Act && Assert Assert.Throws<InvalidOperationException>(() => etag["Name"], "The ETag is not well-formed."); }
public void ApplyToNonGenericThrows_IfPassedAnIQueryableOfTheWrongType() { // Arrange ETag <Customer> etagCustomer = new ETag <Customer> { IsIfNoneMatch = true }; IQueryable query = Enumerable.Empty <int>().AsQueryable(); // Act & Assert Assert.Throws <ArgumentException>( () => etagCustomer.ApplyTo(query), "Cannot apply ETag of 'System.Web.OData.Formatter.Serialization.Models.Customer' to IQueryable of " + "'System.Int32'.\r\nParameter name: query"); }
public void ApplyTo_SameQueryReturned_GivenQueryableAndETagAny() { // Arrange var any = new ETag { IsAny = true }; var customers = _customers.AsQueryable(); // Act var queryable = any.ApplyTo(customers); // Assert Assert.NotNull(queryable); Assert.Same(queryable, customers); }
public void ApplyTo_NewQueryReturned_GivenQueryable() { // Arrange ETag<Customer> etagCustomer = new ETag<Customer>(); dynamic etag = etagCustomer; etag.FirstName = "Foo"; // Act IQueryable queryable = etagCustomer.ApplyTo(_customers.AsQueryable()); // Assert Assert.NotNull(queryable); IEnumerable<Customer> actualCustomers = Assert.IsAssignableFrom<IEnumerable<Customer>>(queryable); Assert.Equal( new[] { 1 }, actualCustomers.Select(customer => customer.ID)); }
public void ApplyTo_NewQueryReturned_GivenQueryable() { // Arrange ETag<Customer> etagCustomer = new ETag<Customer>(); dynamic etag = etagCustomer; etag.FirstName = "Foo"; // Act IQueryable queryable = etagCustomer.ApplyTo(_customers.AsQueryable()); // Assert Assert.NotNull(queryable); IEnumerable<Customer> actualCustomers = Assert.IsAssignableFrom<IEnumerable<Customer>>(queryable); Assert.Equal( new[] { 1 }, actualCustomers.Select(customer => customer.ID)); MethodCallExpression methodCall = queryable.Expression as MethodCallExpression; Assert.NotNull(methodCall); Assert.Equal(2, methodCall.Arguments.Count); Assert.Equal(@"Param_0 => (Param_0.FirstName == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty)", methodCall.Arguments[1].ToString()); }
public void ApplyTo_SameQueryReturned_GivenQueryableAndETagAny() { // Arrange var any = new ETag { IsAny = true }; var customers = _customers.AsQueryable(); // Act var queryable = any.ApplyTo(customers); // Assert Assert.NotNull(queryable); Assert.Same(queryable, customers); }
public void ApplyTo_NewQueryReturned_IsIfNoneMatchWithMultipleConcurrencyProperties() { // Arrange ETag etagCustomer = new ETag { EntityType = typeof(Customer), IsIfNoneMatch = true }; dynamic etag = etagCustomer; etag.FirstName = "Def"; etag.LastName = "Xyz"; // Act IQueryable queryable = etagCustomer.ApplyTo(_customers.AsQueryable()); // Assert Assert.NotNull(queryable); IEnumerable<Customer> actualCustomers = Assert.IsAssignableFrom<IEnumerable<Customer>>(queryable); Assert.Equal( new[] { 1, 2 }, actualCustomers.Select(customer => customer.ID)); MethodCallExpression methodCall = queryable.Expression as MethodCallExpression; Assert.NotNull(methodCall); Assert.Equal(2, methodCall.Arguments.Count); Assert.Equal( @"Param_0 => Not(((Param_0.FirstName == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty) " + "AndAlso (Param_0.LastName == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty)))", methodCall.Arguments[1].ToString()); }
public void ApplyToNonGenericThrows_IfPassedAnIQueryableOfTheWrongType() { // Arrange ETag<Customer> etagCustomer = new ETag<Customer> { IsIfNoneMatch = true }; IQueryable query = Enumerable.Empty<int>().AsQueryable(); // Act & Assert Assert.Throws<ArgumentException>( () => etagCustomer.ApplyTo(query), "Cannot apply ETag of 'System.Web.OData.Formatter.Serialization.Models.Customer' to IQueryable of " + "'System.Int32'.\r\nParameter name: query"); }
public void ApplyTo_NewQueryReturned_ForInteger(sbyte byteVal, short shortVal, bool ifMatch, IList <int> expect) { // Arrange var mycustomers = new List <MyETagOrder> { new MyETagOrder { ID = 1, ByteVal = 7, ShortVal = 8 }, new MyETagOrder { ID = 2, ByteVal = SByte.MaxValue, ShortVal = Int16.MaxValue }, new MyETagOrder { ID = 3, ByteVal = SByte.MinValue, ShortVal = Int16.MinValue }, }; IETagHandler handerl = new DefaultODataETagHandler(); Dictionary <string, object> properties = new Dictionary <string, object> { { "ByteVal", byteVal }, { "ShortVal", shortVal } }; EntityTagHeaderValue etagHeaderValue = handerl.CreateETag(properties); HttpRequestMessage request = new HttpRequestMessage(); HttpConfiguration cofiguration = new HttpConfiguration(); request.SetConfiguration(cofiguration); var builder = new ODataConventionModelBuilder(); builder.EntitySet <MyETagOrder>("Orders"); IEdmModel model = builder.GetEdmModel(); IEdmEntityType order = model.SchemaElements.OfType <IEdmEntityType>().FirstOrDefault(e => e.Name == "MyETagOrder"); IEdmEntitySet orders = model.FindDeclaredEntitySet("Orders"); Mock <ODataPathSegment> mockSegment = new Mock <ODataPathSegment> { CallBase = true }; mockSegment.Setup(s => s.GetEdmType(null)).Returns(order); mockSegment.Setup(s => s.GetNavigationSource(null)).Returns(orders); ODataPath odataPath = new ODataPath(new[] { mockSegment.Object }); request.ODataProperties().Path = odataPath; request.ODataProperties().Model = model; ETag etagCustomer = request.GetETag(etagHeaderValue); etagCustomer.EntityType = typeof(MyETagOrder); etagCustomer.IsIfNoneMatch = !ifMatch; // Act IQueryable queryable = etagCustomer.ApplyTo(mycustomers.AsQueryable()); // Assert Assert.NotNull(queryable); IEnumerable <MyETagOrder> actualOrders = Assert.IsAssignableFrom <IEnumerable <MyETagOrder> >(queryable); Assert.Equal(expect, actualOrders.Select(c => c.ID)); MethodCallExpression methodCall = queryable.Expression as MethodCallExpression; Assert.NotNull(methodCall); Assert.Equal(2, methodCall.Arguments.Count); if (ifMatch) { Assert.Equal( "Param_0 => ((Param_0.ByteVal == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.SByte]).TypedProperty) " + "AndAlso (Param_0.ShortVal == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int16]).TypedProperty))", methodCall.Arguments[1].ToString()); } else { Assert.Equal( "Param_0 => Not(((Param_0.ByteVal == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.SByte]).TypedProperty) " + "AndAlso (Param_0.ShortVal == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Int16]).TypedProperty)))", methodCall.Arguments[1].ToString()); } }
private IQueryable ApplyQueryOptions( IQueryable queryable, ODataPath path, bool applyCount, out bool isIfNoneMatch, out ETag etag) { // ETAG IsIfNoneMatch is changed to public access, this flag can be removed. isIfNoneMatch = false; etag = null; if (this.shouldWriteRawValue) { // Query options don't apply to $value. return queryable; } HttpRequestMessageProperties properties = this.Request.ODataProperties(); var model = Api.GetModelAsync().Result; ODataQueryContext queryContext = new ODataQueryContext(model, queryable.ElementType, path); ODataQueryOptions queryOptions = new ODataQueryOptions(queryContext, this.Request); // Get etag for query request if (queryOptions.IfMatch != null) { etag = queryOptions.IfMatch; } else if (queryOptions.IfNoneMatch != null) { isIfNoneMatch = true; etag = queryOptions.IfNoneMatch; } // TODO GitHubIssue#41 : Ensure stable ordering for query ODataQuerySettings settings = Api.Context.GetApiService<ODataQuerySettings>(); if (this.shouldReturnCount) { // Query options other than $filter and $search don't apply to $count. queryable = queryOptions.ApplyTo( queryable, settings, AllowedQueryOptions.All ^ AllowedQueryOptions.Filter); return queryable; } if (queryOptions.Count != null && !applyCount) { RestierQueryExecutorOptions queryExecutorOptions = Api.Context.GetApiService<RestierQueryExecutorOptions>(); queryExecutorOptions.IncludeTotalCount = queryOptions.Count.Value; queryExecutorOptions.SetTotalCount = value => properties.TotalCount = value; } // Validate query before apply, and query setting like MaxExpansionDepth can be customized here ODataValidationSettings validationSettings = Api.Context.GetApiService<ODataValidationSettings>(); queryOptions.Validate(validationSettings); // Entity count can NOT be evaluated at this point of time because the source // expression is just a placeholder to be replaced by the expression sourcer. if (!applyCount) { queryable = queryOptions.ApplyTo(queryable, settings, AllowedQueryOptions.Count); } else { queryable = queryOptions.ApplyTo(queryable, settings); } return queryable; }
private HttpResponseMessage CreateQueryResponse( IQueryable query, IEdmType edmType, bool isIfNoneMatch, ETag etag) { IEdmTypeReference typeReference = GetTypeReference(edmType); BaseSingleResult singleResult = null; HttpResponseMessage response = null; if (typeReference.IsPrimitive()) { if (this.shouldReturnCount || this.shouldWriteRawValue) { var rawResult = new RawResult(query, typeReference, this.Api.Context); singleResult = rawResult; response = this.Request.CreateResponse(HttpStatusCode.OK, rawResult); } else { var primitiveResult = new PrimitiveResult(query, typeReference, this.Api.Context); singleResult = primitiveResult; response = this.Request.CreateResponse(HttpStatusCode.OK, primitiveResult); } } if (typeReference.IsComplex()) { var complexResult = new ComplexResult(query, typeReference, this.Api.Context); singleResult = complexResult; response = this.Request.CreateResponse(HttpStatusCode.OK, complexResult); } if (typeReference.IsEnum()) { if (this.shouldWriteRawValue) { var rawResult = new RawResult(query, typeReference, this.Api.Context); singleResult = rawResult; response = this.Request.CreateResponse(HttpStatusCode.OK, rawResult); } else { var enumResult = new EnumResult(query, typeReference, this.Api.Context); singleResult = enumResult; response = this.Request.CreateResponse(HttpStatusCode.OK, enumResult); } } if (singleResult != null) { if (singleResult.Result == null) { // Per specification, If the property is single-valued and has the null value, // the service responds with 204 No Content. return this.Request.CreateResponse(HttpStatusCode.NoContent); } return response; } if (typeReference.IsCollection()) { var elementType = typeReference.AsCollection().ElementType(); if (elementType.IsPrimitive() || elementType.IsEnum()) { return this.Request.CreateResponse( HttpStatusCode.OK, new NonResourceCollectionResult(query, typeReference, this.Api.Context)); } return this.Request.CreateResponse( HttpStatusCode.OK, new ResourceSetResult(query, typeReference, this.Api.Context)); } var entityResult = query.SingleOrDefault(); if (entityResult == null) { return this.Request.CreateResponse(HttpStatusCode.NoContent); } // Check the ETag here if (etag != null) { // request with If-Match header, if match, then should return whole content // request with If-Match header, if not match, then should return 412 // request with If-None-Match header, if match, then should return 304 // request with If-None-Match header, if not match, then should return whole content etag.EntityType = query.ElementType; query = etag.ApplyTo(query); entityResult = query.SingleOrDefault(); if (entityResult == null && !isIfNoneMatch) { return this.Request.CreateResponse(HttpStatusCode.PreconditionFailed); } else if (entityResult == null) { return this.Request.CreateResponse(HttpStatusCode.NotModified); } } // Using reflection to create response for single entity so passed in parameter is not object type, // but will be type of real entity type, then EtagMessageHandler can be used to set ETAG header // when response is single entity. // There are three HttpRequestMessageExtensions class defined in different assembles var genericMethod = typeof(System.Net.Http.HttpRequestMessageExtensions).GetMethods() .Where(m => m.Name == "CreateResponse" && m.GetParameters().Length == 3); var method = genericMethod.FirstOrDefault().MakeGenericMethod(query.ElementType); response = method.Invoke(null, new object[] { this.Request, HttpStatusCode.OK, entityResult }) as HttpResponseMessage; return response; }
public void ApplyTo_NewQueryReturned_ForDouble(double value, bool ifMatch, IList <int> expect) { // Arrange var myCustomers = new List <MyETagCustomer> { new MyETagCustomer { ID = 1, DoubleETag = 1.0, }, new MyETagCustomer { ID = 2, DoubleETag = 1.1, }, new MyETagCustomer { ID = 3, DoubleETag = 1.0, }, }; IETagHandler handerl = new DefaultODataETagHandler(); Dictionary <string, object> properties = new Dictionary <string, object> { { "DoubleETag", value } }; EntityTagHeaderValue etagHeaderValue = handerl.CreateETag(properties); HttpRequestMessage request = new HttpRequestMessage(); var builder = new ODataConventionModelBuilder(); builder.EntitySet <MyETagCustomer>("Customers"); IEdmModel model = builder.GetEdmModel(); IEdmEntityType customer = model.SchemaElements.OfType <IEdmEntityType>().FirstOrDefault(e => e.Name == "MyEtagCustomer"); IEdmEntitySet customers = model.FindDeclaredEntitySet("Customers"); ODataPath odataPath = new ODataPath(new[] { new EntitySetSegment(customers) }); request.EnableHttpDependencyInjectionSupport(model); request.ODataProperties().Path = odataPath; ETag etagCustomer = request.GetETag(etagHeaderValue); etagCustomer.EntityType = typeof(MyETagCustomer); etagCustomer.IsIfNoneMatch = !ifMatch; // Act IQueryable queryable = etagCustomer.ApplyTo(myCustomers.AsQueryable()); // Assert Assert.NotNull(queryable); IList <MyETagCustomer> actualCustomers = Assert.IsAssignableFrom <IEnumerable <MyETagCustomer> >(queryable).ToList(); if (expect != null) { Assert.Equal(expect, actualCustomers.Select(c => c.ID)); } MethodCallExpression methodCall = queryable.Expression as MethodCallExpression; Assert.NotNull(methodCall); Assert.Equal(2, methodCall.Arguments.Count); if (ifMatch) { Assert.Equal( "Param_0 => (Param_0.DoubleETag == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Double]).TypedProperty)", methodCall.Arguments[1].ToString()); } else { Assert.Equal( "Param_0 => Not((Param_0.DoubleETag == value(System.Web.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.Double]).TypedProperty))", methodCall.Arguments[1].ToString()); } }