1+ // Copyright (c) Microsoft Corporation. All rights reserved.
2+ // Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+ using System . Linq ;
5+ using System . Net . Http ;
6+ using System . Web . Http ;
7+ using System . Web . OData ;
8+ using System . Web . OData . Extensions ;
9+ using System . Web . OData . Routing ;
10+ using System . Web . OData . Routing . Conventions ;
11+ using Microsoft . OData . Core ;
12+ using Microsoft . OData . Edm ;
13+ using Microsoft . OData . Edm . Annotations ;
14+ using Microsoft . OData . Edm . Expressions ;
15+ using Microsoft . OData . Edm . Library ;
16+ using Microsoft . OData . Edm . Vocabularies . V1 ;
17+ using Newtonsoft . Json . Linq ;
18+ using Nuwa ;
19+ using WebStack . QA . Test . OData . ModelBuilder ;
20+ using Xunit ;
21+
22+ namespace WebStack . QA . Test . OData . ETags
23+ {
24+ [ NuwaFramework ]
25+ public class ETagsUntypedTests
26+ {
27+ [ NuwaBaseAddress ]
28+ public string BaseAddress { get ; set ; }
29+
30+ [ NuwaHttpClient ]
31+ public HttpClient Client { get ; set ; }
32+
33+ [ NuwaConfiguration ]
34+ public static void UpdateConfiguration ( HttpConfiguration configuration )
35+ {
36+ configuration . Routes . Clear ( ) ;
37+ configuration . MapODataServiceRoute ( "odata" , "odata" , GetEdmModel ( ) , new DefaultODataPathHandler ( ) , ODataRoutingConventions . CreateDefault ( ) ) ;
38+ configuration . MessageHandlers . Add ( new ETagMessageHandler ( ) ) ;
39+ }
40+
41+ private static IEdmModel GetEdmModel ( )
42+ {
43+ EdmModel model = new EdmModel ( ) ;
44+
45+ // entity type customer
46+ EdmEntityType customer = new EdmEntityType ( "NS" , "Customer" ) ;
47+ customer . AddKeys ( customer . AddStructuralProperty ( "ID" , EdmPrimitiveTypeKind . Int32 ) ) ;
48+ IEdmStructuralProperty customerName = customer . AddStructuralProperty ( "Name" , EdmPrimitiveTypeKind . String ) ;
49+ model . AddElement ( customer ) ;
50+
51+ // entity sets
52+ EdmEntityContainer container = new EdmEntityContainer ( "NS" , "Default" ) ;
53+ model . AddElement ( container ) ;
54+ EdmEntitySet customers = container . AddEntitySet ( "ETagUntypedCustomers" , customer ) ;
55+
56+ model . SetOptimisticConcurrencyAnnotation ( customers , new [ ] { customerName } ) ;
57+
58+ return model ;
59+ }
60+
61+ [ Fact ]
62+ public void ModelBuilderTest ( )
63+ {
64+ const string expectMetadata =
65+ " <EntitySet Name=\" ETagUntypedCustomers\" EntityType=\" NS.Customer\" >\r \n " +
66+ " <Annotation Term=\" Org.OData.Core.V1.OptimisticConcurrency\" >\r \n " +
67+ " <Collection>\r \n " +
68+ " <PropertyPath>Name</PropertyPath>\r \n " +
69+ " </Collection>\r \n " +
70+ " </Annotation>\r \n " +
71+ " </EntitySet>" ;
72+
73+ string requestUri = string . Format ( "{0}/odata/$metadata" , this . BaseAddress ) ;
74+
75+ HttpResponseMessage response = this . Client . GetAsync ( requestUri ) . Result ;
76+
77+ var content = response . Content . ReadAsStringAsync ( ) . Result ;
78+ Assert . Contains ( expectMetadata , content ) ;
79+
80+ var stream = response . Content . ReadAsStreamAsync ( ) . Result ;
81+ IODataResponseMessage message = new ODataMessageWrapper ( stream , response . Content . Headers ) ;
82+ var reader = new ODataMessageReader ( message ) ;
83+ var edmModel = reader . ReadMetadataDocument ( ) ;
84+ Assert . NotNull ( edmModel ) ;
85+
86+ var etagCustomers = edmModel . FindDeclaredEntitySet ( "ETagUntypedCustomers" ) ;
87+ Assert . NotNull ( etagCustomers ) ;
88+
89+ var annotations = edmModel . FindDeclaredVocabularyAnnotations ( etagCustomers ) ;
90+ IEdmVocabularyAnnotation annotation = Assert . Single ( annotations ) ;
91+ Assert . NotNull ( annotation ) ;
92+
93+ Assert . Same ( CoreVocabularyModel . ConcurrencyTerm , annotation . Term ) ;
94+ Assert . Same ( etagCustomers , annotation . Target ) ;
95+
96+ IEdmValueAnnotation valueAnnotation = annotation as IEdmValueAnnotation ;
97+ Assert . NotNull ( valueAnnotation ) ;
98+ Assert . NotNull ( valueAnnotation . Value ) ;
99+
100+ IEdmCollectionExpression collection = valueAnnotation . Value as IEdmCollectionExpression ;
101+ Assert . NotNull ( collection ) ;
102+ Assert . Equal ( new [ ] { "Name" } , collection . Elements . Select ( e => ( ( IEdmPathExpression ) e ) . Path . Single ( ) ) ) ;
103+ }
104+
105+ [ Fact ]
106+ public void PatchUpdatedEntryWithIfMatchShouldReturnPreconditionFailed ( )
107+ {
108+ string requestUri = this . BaseAddress + "/odata/ETagUntypedCustomers(1)?$format=json" ;
109+
110+ HttpRequestMessage request = new HttpRequestMessage ( HttpMethod . Get , requestUri ) ;
111+ HttpResponseMessage response = this . Client . SendAsync ( request ) . Result ;
112+
113+ Assert . True ( response . IsSuccessStatusCode ) ;
114+ var etagInHeader = response . Headers . ETag . ToString ( ) ;
115+ JObject result = response . Content . ReadAsAsync < JObject > ( ) . Result ;
116+ var etagInPayload = ( string ) result [ "@odata.etag" ] ;
117+
118+ Assert . True ( etagInPayload == etagInHeader ) ;
119+ Assert . Equal ( etagInPayload , "W/\" J1NhbSc=\" " ) ;
120+ }
121+ }
122+
123+ public class ETagUntypedCustomersController : ODataController
124+ {
125+ [ EnableQuery ]
126+ public IHttpActionResult Get ( int key )
127+ {
128+ IEdmModel model = Request . ODataProperties ( ) . Model ;
129+ IEdmEntityType entityType = model . SchemaElements . OfType < IEdmEntityType > ( ) . First ( c => c . Name == "Customer" ) ;
130+ EdmEntityObject customer = new EdmEntityObject ( entityType ) ;
131+ customer . TrySetPropertyValue ( "ID" , key ) ;
132+ customer . TrySetPropertyValue ( "Name" , "Sam" ) ;
133+ return Ok ( customer ) ;
134+ }
135+ }
136+ }
0 commit comments