diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Tests/TrippinInMemoryE2ETest.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Tests/TrippinInMemoryE2ETest.cs index 49e03f11..d8079a63 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Tests/TrippinInMemoryE2ETest.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Tests/TrippinInMemoryE2ETest.cs @@ -37,49 +37,63 @@ public void TestImperativeViewEntitySet() [Fact] public void TestCollectionOfPrimitivePropertyAccess() { - TestGetPayloadContains("People(1)/Emails", - "\"@odata.context\":\"http://localhost:21248/api/Trippin/$metadata#Collection(Edm.String)\""); - TestGetPayloadContains("People(7)/Emails", + TestGetPayloadContains("People('russellwhyte')/Emails", + "\"@odata.context\":\"http://localhost:21248/"); + TestGetPayloadContains("People('russellwhyte')/Emails", + "api/Trippin/$metadata#Collection(Edm.String)\""); + + TestGetPayloadContains("People('russellwhyte')/Emails", "\"value\":["); } [Fact] public void TestCollectionOfComplexPropertyAccess() { - TestGetPayloadContains("People(1)/Locations", - "\"@odata.context\":\"http://localhost:21248/api/Trippin/$metadata#Collection(" + + var reqStr = "People('russellwhyte')/AddressInfo"; + TestGetPayloadContains(reqStr, + "\"@odata.context\":\"http://localhost:21248/"); + TestGetPayloadContains(reqStr, + "api/Trippin/$metadata#Collection(" + "Microsoft.OData.Service.Sample.TrippinInMemory.Models.Location)\""); } [Fact] public void TestCollectionOfEnumPropertyAccess() { - TestGetPayloadContains("People(1)/Features", - "\"@odata.context\":\"http://localhost:21248/api/Trippin/$metadata#Collection(" + + var reqStr = "People('russellwhyte')/Features"; + TestGetPayloadContains(reqStr, + "\"@odata.context\":\"http://localhost:21248/"); + TestGetPayloadContains(reqStr, + "$metadata#Collection(" + "Microsoft.OData.Service.Sample.TrippinInMemory.Models.Feature)\""); } [Fact] public void TestEnumPropertyAccess() { - TestGetPayloadContains("People(1)/FavoriteFeature", - "\"@odata.context\":\"http://localhost:21248/api/Trippin/$metadata#People(1)/FavoriteFeature"); + var reqStr = "People('russellwhyte')/FavoriteFeature"; + TestGetPayloadContains(reqStr, + "\"@odata.context\":\"http://localhost:21248/"); + TestGetPayloadContains(reqStr, + "$metadata#" + reqStr); } [Fact] public void TestRawValuedEnumPropertyAccess() { - TestGetPayloadIs("People(1)/FavoriteFeature/$value", "Feature1"); + TestGetPayloadIs("People('russellwhyte')/FavoriteFeature/$value", "Feature1"); } [Fact] public void TestCountCollectionOfStructuralProperty() { - TestGetPayloadIs("People(1)/Emails/$count", "2"); - TestGetPayloadIs("People(1)/Locations/$count", "2"); - TestGetPayloadIs("People(1)/Features/$count", "2"); + TestGetPayloadIs("People('russellwhyte')/Emails/$count", "2"); + TestGetPayloadIs("People('russellwhyte')/AddressInfo/$count", "1"); } + /// + /// TODO t-pewang, this case cannot pass, since my navigation property doesn't auto expand + /// [Fact] public void TestAutoExpandedNavigationProperty() { @@ -87,43 +101,43 @@ public void TestAutoExpandedNavigationProperty() } [Theory] - // Single primitive property with null value - [InlineData("/People(5)/MiddleName", 204)] - // Single primitive property $value with null value - [InlineData("/People(5)/MiddleName/$value", 204)] - // Collection of primitive property with empty value - [InlineData("/People(5)/Emails", 200)] - // Collection of primitive property $value with null value, should throw exception - // TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method - [InlineData("/People(5)/Emails/$value", 404)] + // Single primitive property with null value + [InlineData("/People('willieashmore')/MiddleName", 204)] + // Single primitive property $value with null value + [InlineData("/People('willieashmore')/MiddleName/$value", 204)] + // Collection of primitive property with empty value + [InlineData("/People('willieashmore')/Emails", 200)] + //// Collection of primitive property $value with null value, should throw exception + //// TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method + //[InlineData("/People('willieashmore')/Emails/$value", 404)] // Collection of primitive property with null collection - [InlineData("/People(7)/Emails", 200)] + [InlineData("/People('clydeguess')/Emails", 200)] // single complex property with null value - [InlineData("/People(5)/HomeAddress", 204)] + [InlineData("/People('willieashmore')/HomeAddress", 204)] // single complex property's propery and complex property has null value - [InlineData("/People(5)/HomeAddress/Address", 404)] - // single complex property's property with null value - [InlineData("/People(6)/HomeAddress/Address", 204)] + [InlineData("/People('willieashmore')/HomeAddress/Address", 404)] + // single complex property's property with null value + [InlineData("/People('clydeguess')/HomeAddress/Address", 204)] // collection of complex property with empty collection value - [InlineData("/People(5)/Locations", 200)] - // collection of complex property's propery and collection of complex property has null value - // TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method - [InlineData("/People(5)/Locations/Address", 404)] + [InlineData("/People('willieashmore')/AddressInfo", 200)] + //// collection of complex property's propery and collection of complex property has null value + //// TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method + //[InlineData("/People(5)/AddressInfo/Address", 404)] // Collection of complex property with null collection - [InlineData("/People(7)/Locations", 200)] + [InlineData("/People('clydeguess')/AddressInfo", 200)] // single navigation property with null value - [InlineData("/People(5)/BestFriend", 204)] + [InlineData("/People('willieashmore')/BestFriend", 204)] // single navigation property's propery and navigation property has null value - [InlineData("/People(5)/BestFriend/MiddleName", 404)] + [InlineData("/People('willieashmore')/BestFriend/MiddleName", 404)] // single navigation property's property with null value - [InlineData("/People(6)/BestFriend/MiddleName", 204)] + [InlineData("/People('russellwhyte')/BestFriend/MiddleName", 204)] // collection of navigation property with empty collection value - [InlineData("/People(5)/Friends", 200)] + [InlineData("/People('willieashmore')/Friends", 200)] // collection of navigation property with null collection value - [InlineData("/People(7)/Trips", 200)] - // collection of navigation property's property and navigation property has null value - // TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method - [InlineData("/People(5)/Friends/MiddleName", 404)] + [InlineData("/People('clydeguess')/Trips", 200)] + //// collection of navigation property's property and navigation property has null value + //// TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method + //[InlineData("/People('willieashmore')/Friends/MiddleName", 404)] public void QueryPropertyWithNullValueStatusCode(string url, int expectedCode) { TestGetStatusCodeIs(url, expectedCode); @@ -131,32 +145,32 @@ public void QueryPropertyWithNullValueStatusCode(string url, int expectedCode) [Theory] // Single primitive property - [InlineData("/People(15)/MiddleName", 404)] + [InlineData("/People('NoneExist')/MiddleName", 404)] // Single primitive property $value - [InlineData("/People(15)/MiddleName/$value", 404)] - // Collection of primitive property - [InlineData("/People(15)/Emails", 404)] - // Collection of primitive property $value - // TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method - [InlineData("/People(15)/Emails/$value", 404)] + [InlineData("/People('NoneExist')/MiddleName/$value", 404)] + // Collection of primitive property + [InlineData("/People('NoneExist')/Emails", 404)] + //// Collection of primitive property $value + //// TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method + //[InlineData("/People('NoneExist')/Emails/$value", 404)] // single complex property - [InlineData("/People(15)/HomeAddress", 404)] + [InlineData("/People('NoneExist')/HomeAddress", 404)] // single complex property's property - [InlineData("/People(15)/HomeAddress/Address", 404)] + [InlineData("/People('NoneExist')/HomeAddress/Address", 404)] // collection of complex property - [InlineData("/People(15)/Locations", 404)] - // collection of complex property's propery - // TODO should be bad request 400 as this is not allowed?? 404 is returned by WebApi Route Match method - [InlineData("/People(15)/Locations/Address", 404)] + [InlineData("/People('NoneExist')/AddressInfo", 404)] + //// collection of complex property's propery + //// TODO should be bad request 400 as this is not allowed?? 404 is returned by WebApi Route Match method + //[InlineData("/People('NoneExist')/Locations/Address", 404)] // single navigation property - [InlineData("/People(15)/BestFriend", 404)] + [InlineData("/People('NoneExist')/BestFriend", 404)] // single navigation property's propery - [InlineData("/People(15)/BestFriend/MiddleName", 404)] + [InlineData("/People('NoneExist')/BestFriend/MiddleName", 404)] // collection of navigation property - [InlineData("/People(15)/Friends", 404)] - // collection of navigation property's property - // TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method - [InlineData("/People(15)/Friends/MiddleName", 404)] + [InlineData("/People('NoneExist')/Friends", 404)] + //// collection of navigation property's property + //// TODO should be bad request 400 as this is not allowed, 404 is returned by WebApi Route Match method + //[InlineData("/People('NoneExist')/Friends/MiddleName", 404)] public void QueryPropertyWithNonExistEntity(string url, int expectedCode) { TestGetStatusCodeIs(url, expectedCode); diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs index 2e80b5b2..be25efeb 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs @@ -52,6 +52,15 @@ public IQueryable People } } + public IQueryable NewComePeople + { + get + { + var datasource = _dataStoreManager.GetDataStoreInstance(Key); + return datasource?.People.AsQueryable(); + } + } + public Person Me { get @@ -177,7 +186,6 @@ public Airline GetFavoriteAirline(Person person) return Airlines.Single(a => a.AirlineCode.Equals(favoriteAirlineCode)); } - /// /// Bound Function, get the trips of one friend with userName /// @@ -427,15 +435,29 @@ private static void SetValues(object instance, Type type, IReadOnlyDictionary; - if (dic == null) + var col = value as System.Web.OData.EdmComplexObjectCollection; + + if (dic != null) + { + value = Activator.CreateInstance(propertyInfo.PropertyType); + SetValues(value, propertyInfo.PropertyType, dic); + } + else if (col != null) + { + var realType = propertyInfo.PropertyType.GenericTypeArguments[0]; + var valueType = typeof(Collection<>).MakeGenericType(realType); + value = Activator.CreateInstance(valueType); + foreach (var c in col) + { + value.GetType().GetMethod("Add").Invoke(value, new[] {c}); + } + } + else { throw new NotSupportedException(string.Format( CultureInfo.InvariantCulture, propertyPair.Key)); } - - value = Activator.CreateInstance(propertyInfo.PropertyType); - SetValues(value, propertyInfo.PropertyType, dic); } propertyInfo.SetValue(instance, value); diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/App_Start/WebApiConfig.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/App_Start/WebApiConfig.cs index 8c7c9f47..ace3158f 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/App_Start/WebApiConfig.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/App_Start/WebApiConfig.cs @@ -14,6 +14,7 @@ public static class WebApiConfig public static void Register(HttpConfiguration config) { RegisterTrippin(config, GlobalConfiguration.DefaultServer); + config.SetUseVerboseErrors(true); config.MessageHandlers.Add(new ETagMessageHandler()); } @@ -21,8 +22,8 @@ public static async void RegisterTrippin( HttpConfiguration config, HttpServer server) { await config.MapRestierRoute( - "TrippinApi", - null, //"api/Trippin", + "TrippinApi", + "api/Trippin", new RestierBatchHandler(server)); } } diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/Person.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/Person.cs index 1e501b45..0d70437b 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/Person.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/Person.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Web.OData.Builder; namespace Microsoft.OData.Service.Sample.TrippinInMemory.Models { @@ -13,6 +14,14 @@ public enum PersonGender Unknow } + public enum Feature + { + Feature1, + Feature2, + Feature3, + Feature4 + } + public class Person { [Key] @@ -25,6 +34,8 @@ public class Person [MaxLength(26), MinLength(1)] public string LastName { get; set; } + public string MiddleName { get; set; } + public PersonGender Gender { get; set; } public long? Age { get; set; } @@ -33,10 +44,19 @@ public class Person public ICollection AddressInfo { get; set; } + public Location HomeAddress { get; set; } + + [AutoExpand] public virtual ICollection Friends { get; set; } + public Person BestFriend { get; set; } + public virtual ICollection Trips { get; set; } + public Feature FavoriteFeature { get; set; } + + public virtual ICollection Features { get; set; } + [ConcurrencyCheck] public long Concurrency { get; set; } } diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/TripPinDataSource.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/TripPinDataSource.cs index 30410646..dafec4aa 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/TripPinDataSource.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Models/TripPinDataSource.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Web.OData.Builder; using Microsoft.Spatial; namespace Microsoft.OData.Service.Sample.TrippinInMemory.Models @@ -302,7 +301,13 @@ private void Initialize() StartsAt = new DateTime(2014, 2, 1), EndsAt = new DateTime(2014, 2, 4) } - } + }, + Features = new List + { + Feature.Feature1, + Feature.Feature2 + }, + FavoriteFeature = Feature.Feature1 }, new Person() { @@ -518,20 +523,8 @@ private void Initialize() LastName = "Ashmore", UserName = "willieashmore", Gender = PersonGender.Male, - Emails = new List { "Willie@example.com", "Willie@contoso.com" }, - AddressInfo = new List - { - new Location() - { - Address = "89 Jefferson Way Suite 2", - City = new City() - { - CountryRegion = "United States", - Name = "Portland", - Region = "WA" - } - } - }, + Emails = new List(), + AddressInfo = new List(), Trips = new List { new Trip() @@ -599,34 +592,7 @@ private void Initialize() LastName = "Guess", UserName = "clydeguess", Gender = PersonGender.Male, - Emails = new List { "Clyde@example.com" }, - AddressInfo = new List - { - new Location() - { - Address = "55 Grizzly Peak Rd.", - City = new City() - { - CountryRegion = "United States", - Name = "Butte", - Region = "MT" - } - } - }, - Trips = new List - { - new Trip() - { - TripId = 10, - ShareId = new Guid("a88f675d-9199-4392-9656-b08e3b46df8a"), - Name = "Study trip", - Budget = 1550.3f, - Description = "This is a 2 weeks study trip", - Tags = new List{"study"}, - StartsAt = new DateTimeOffset(new DateTime(2014, 1, 1)), - EndsAt = new DateTimeOffset(new DateTime(2014, 1, 14)) - } - } + HomeAddress = new Location() }, new Person() { @@ -1100,6 +1066,10 @@ private void Initialize() People.Single(p => p.UserName == "ronaldmundy"), People.Single(p => p.UserName == "javieralfred") }; + + People.Single(p => p.UserName == "russellwhyte").BestFriend= + People.Single(p => p.UserName == "scottketchum"); + People.Single(p => p.UserName == "scottketchum").Friends = new Collection() { People.Single(p => p.UserName == "russellwhyte"),