7
7
using System . Text ;
8
8
using Optimizely . Graph . Source . Sdk . RestClientHelpers ;
9
9
using Optimizely . Graph . Source . Sdk . SourceConfiguration ;
10
+ using Optimizely . Graph . Source . Sdk . Tests . ExampleObjects ;
10
11
11
12
namespace Optimizely . Graph . Source . Sdk . Tests . RepositoryTests
12
13
{
@@ -24,6 +25,12 @@ public GraphSourceRepositoryTests()
24
25
repository = new GraphSourceRepository ( mockRestClient . Object , source ) ;
25
26
}
26
27
28
+ [ TestInitialize ]
29
+ public void TestInit ( )
30
+ {
31
+ SourceConfigurationModel . Reset ( ) ;
32
+ }
33
+
27
34
[ TestMethod ]
28
35
public void Constructor_WithEmptySource_ThrowsArgumentNullException ( )
29
36
{
@@ -114,6 +121,123 @@ public async Task SaveTypesAsync_BuildsExpectedJsonString_AndCallsGraphClient()
114
121
mockRestClient . VerifyAll ( ) ;
115
122
}
116
123
124
+ [ TestMethod ]
125
+ public async Task SaveTypesAsync_WithLink_ShouldGenerateTypesAndLink ( )
126
+ {
127
+ // Arrange
128
+ repository . ConfigureContentType < Location > ( )
129
+ . Field ( x => x . Longitude , IndexingType . Queryable )
130
+ . Field ( x => x . Latitude , IndexingType . Queryable )
131
+ . Field ( x => x . Name , IndexingType . Searchable ) ;
132
+
133
+ repository . ConfigureContentType < Event > ( )
134
+ . Field ( x => x . LocationName , IndexingType . Queryable )
135
+ . Field ( x => x . Time , IndexingType . Queryable )
136
+ . Field ( x => x . Name , IndexingType . Searchable )
137
+ . Field ( x => x . AdditionalInfo , IndexingType . PropertyType ) ;
138
+
139
+ repository . ConfigureContentType < ExtraInfo > ( )
140
+ . Field ( x => x . Example1 , IndexingType . OnlyStored )
141
+ . Field ( x => x . Example2 , IndexingType . Queryable ) ;
142
+
143
+ repository . ConfigureLink < Location , Event > (
144
+ "NameToLocationName" ,
145
+ x => x . Name ,
146
+ x => x . LocationName
147
+ ) ;
148
+
149
+ var expectedJsonString = @"{
150
+ ""useTypedFieldNames"": true,
151
+ ""languages"": [],
152
+ ""links"": {
153
+ ""NameToLocationName"": {
154
+ ""from"": ""Name$$String___searchable"",
155
+ ""to"": ""LocationName$$String""
156
+ }
157
+ },
158
+ ""contentTypes"": {
159
+ ""Location"": {
160
+ ""contentType"": [],
161
+ ""properties"": {
162
+ ""Longitude"": {
163
+ ""type"": ""Float"",
164
+ ""searchable"": false,
165
+ ""skip"": false
166
+ },
167
+ ""Latitude"": {
168
+ ""type"": ""Float"",
169
+ ""searchable"": false,
170
+ ""skip"": false
171
+ },
172
+ ""Name"": {
173
+ ""type"": ""String"",
174
+ ""searchable"": true,
175
+ ""skip"": false
176
+ }
177
+ }
178
+ },
179
+ ""Event"": {
180
+ ""contentType"": [],
181
+ ""properties"": {
182
+ ""LocationName"": {
183
+ ""type"": ""String"",
184
+ ""searchable"": false,
185
+ ""skip"": false
186
+ },
187
+ ""Time"": {
188
+ ""type"": ""DateTime"",
189
+ ""searchable"": false,
190
+ ""skip"": false
191
+ },
192
+ ""Name"": {
193
+ ""type"": ""String"",
194
+ ""searchable"": true,
195
+ ""skip"": false
196
+ },
197
+ ""AdditionalInfo"": {
198
+ ""type"": ""ExtraInfo""
199
+ }
200
+ }
201
+ },
202
+ ""ExtraInfo"": {
203
+ ""contentType"": [],
204
+ ""properties"": {
205
+ ""Example1"": {
206
+ ""type"": ""String"",
207
+ ""searchable"": false,
208
+ ""skip"": true
209
+ },
210
+ ""Example2"": {
211
+ ""type"": ""Int"",
212
+ ""searchable"": false,
213
+ ""skip"": false
214
+ }
215
+ }
216
+ }
217
+ },
218
+ ""propertyTypes"": {}
219
+ }" ;
220
+
221
+ var jsonString = BuildExpectedTypeJsonString ( ) ;
222
+ var content = new StringContent ( jsonString , Encoding . UTF8 , "application/json" ) ;
223
+
224
+ var response = new HttpResponseMessage ( HttpStatusCode . OK ) ;
225
+ var request = new HttpRequestMessage ( HttpMethod . Put , $ "/api/content/v3/types?id={ source } ") { Content = content } ;
226
+
227
+ mockRestClient . Setup ( c => c . SendAsync ( It . IsAny < HttpRequestMessage > ( ) ) ) . ReturnsAsync ( response ) ;
228
+ mockRestClient . Setup ( c => c . HandleResponse ( response ) ) ;
229
+
230
+ // Act
231
+ await repository . SaveTypesAsync ( ) ;
232
+
233
+ // Assert
234
+ Assert . AreEqual ( expectedJsonString , jsonString ) ;
235
+
236
+ mockRestClient . Verify ( c => c . SendAsync ( It . Is < HttpRequestMessage > ( x => Compare ( request , x ) ) ) , Times . Once ) ;
237
+ mockRestClient . Verify ( c => c . HandleResponse ( response ) , Times . Once ) ;
238
+ mockRestClient . VerifyAll ( ) ;
239
+ }
240
+
117
241
[ TestMethod ]
118
242
public async Task SaveContentAsync_SerializesData_AndCallsGraphClient ( )
119
243
{
@@ -140,7 +264,7 @@ public async Task SaveContentAsync_SerializesData_AndCallsGraphClient()
140
264
}
141
265
} ;
142
266
143
- var expectedJsonString = BuildExpextedContentJsonString ( exampleData ) ;
267
+ var expectedJsonString = BuildExpextedContentJsonString ( x => x . ToString ( ) , exampleData ) ;
144
268
145
269
var content = new StringContent ( expectedJsonString , Encoding . UTF8 , "application/json" ) ;
146
270
@@ -159,6 +283,118 @@ public async Task SaveContentAsync_SerializesData_AndCallsGraphClient()
159
283
mockRestClient . VerifyAll ( ) ;
160
284
}
161
285
286
+ [ TestMethod ]
287
+ public async Task SaveContentAsync_WithMultipleTypes_ShouldGenerateJsonForContentOfDifferentTypes ( )
288
+ {
289
+ // Arrange
290
+ repository . ConfigureContentType < Location > ( )
291
+ . Field ( x => x . Longitude , IndexingType . Queryable )
292
+ . Field ( x => x . Latitude , IndexingType . Queryable )
293
+ . Field ( x => x . Name , IndexingType . Searchable ) ;
294
+
295
+ repository . ConfigureContentType < Event > ( )
296
+ . Field ( x => x . LocationName , IndexingType . Queryable )
297
+ . Field ( x => x . Time , IndexingType . Queryable )
298
+ . Field ( x => x . Name , IndexingType . Searchable )
299
+ . Field ( x => x . AdditionalInfo , IndexingType . PropertyType ) ;
300
+
301
+ repository . ConfigureContentType < ExtraInfo > ( )
302
+ . Field ( x => x . Example1 , IndexingType . OnlyStored )
303
+ . Field ( x => x . Example2 , IndexingType . Queryable ) ;
304
+
305
+ var locationStockholm = new Location
306
+ {
307
+ Name = "Stockholm" ,
308
+ Latitude = 59.334591 ,
309
+ Longitude = 18.063241 ,
310
+ } ;
311
+ var locationLondon = new Location
312
+ {
313
+ Name = "London" ,
314
+ Latitude = 51.5072 ,
315
+ Longitude = 0.1275 ,
316
+ } ;
317
+ var event1 = new Event
318
+ {
319
+ Name = "Future of Project Management" ,
320
+ Time = new DateTime ( 2024 , 10 , 22 ) ,
321
+ LocationName = "Stockholm" ,
322
+ AdditionalInfo = new ExtraInfo
323
+ {
324
+ Example1 = "test1" ,
325
+ Example2 = 1
326
+ }
327
+ } ;
328
+ var event2 = new Event
329
+ {
330
+ Name = "Week of Hope: Football Camp for Homeless Children in Hanoi!" ,
331
+ Time = new DateTime ( 2024 , 10 , 27 ) ,
332
+ LocationName = "Hanoi" ,
333
+ AdditionalInfo = new ExtraInfo
334
+ {
335
+ Example1 = "test2" ,
336
+ Example2 = 2
337
+ }
338
+ } ;
339
+ var event3 = new Event
340
+ {
341
+ Name = "Optimizing Project Management: Strategies for Success" ,
342
+ Time = new DateTime ( 2024 , 11 , 03 ) ,
343
+ LocationName = "London" ,
344
+ AdditionalInfo = new ExtraInfo
345
+ {
346
+ Example1 = "test3" ,
347
+ Example2 = 3
348
+ }
349
+ } ;
350
+
351
+ var expectedJsonString = @"{ ""index"": { ""_id"": ""Location-Stockholm"", ""language_routing"": ""en"" } }
352
+ { ""Status$$String"": ""Published"", ""__typename"": ""Location"", ""_rbac"": ""r:Everyone:Read"", ""ContentType$$String"": [ ""Location"" ], ""Language"": { ""Name$$String"": ""en"" }, ""Longitude$$Float"": 18.063241, ""Latitude$$Float"": 59.334591, ""Name$$String___searchable"": ""Stockholm""}
353
+ { ""index"": { ""_id"": ""Location-London"", ""language_routing"": ""en"" } }
354
+ { ""Status$$String"": ""Published"", ""__typename"": ""Location"", ""_rbac"": ""r:Everyone:Read"", ""ContentType$$String"": [ ""Location"" ], ""Language"": { ""Name$$String"": ""en"" }, ""Longitude$$Float"": 0.1275, ""Latitude$$Float"": 51.5072, ""Name$$String___searchable"": ""London""}
355
+ { ""index"": { ""_id"": ""Event-Future of Project Management"", ""language_routing"": ""en"" } }
356
+ { ""Status$$String"": ""Published"", ""__typename"": ""Event"", ""_rbac"": ""r:Everyone:Read"", ""ContentType$$String"": [ ""Event"" ], ""Language"": { ""Name$$String"": ""en"" }, ""LocationName$$String"": ""Stockholm"", ""Time$$DateTime"": ""2024-10-21T22:00:00Z"", ""Name$$String___searchable"": ""Future of Project Management"", ""AdditionalInfo"": { ""Example1$$String___skip"": ""test1"", ""Example2$$Int"": 1 }}
357
+ { ""index"": { ""_id"": ""Event-Week of Hope: Football Camp for Homeless Children in Hanoi!"", ""language_routing"": ""en"" } }
358
+ { ""Status$$String"": ""Published"", ""__typename"": ""Event"", ""_rbac"": ""r:Everyone:Read"", ""ContentType$$String"": [ ""Event"" ], ""Language"": { ""Name$$String"": ""en"" }, ""LocationName$$String"": ""Hanoi"", ""Time$$DateTime"": ""2024-10-26T22:00:00Z"", ""Name$$String___searchable"": ""Week of Hope: Football Camp for Homeless Children in Hanoi!"", ""AdditionalInfo"": { ""Example1$$String___skip"": ""test2"", ""Example2$$Int"": 2 }}
359
+ { ""index"": { ""_id"": ""Event-Optimizing Project Management: Strategies for Success"", ""language_routing"": ""en"" } }
360
+ { ""Status$$String"": ""Published"", ""__typename"": ""Event"", ""_rbac"": ""r:Everyone:Read"", ""ContentType$$String"": [ ""Event"" ], ""Language"": { ""Name$$String"": ""en"" }, ""LocationName$$String"": ""London"", ""Time$$DateTime"": ""2024-11-02T23:00:00Z"", ""Name$$String___searchable"": ""Optimizing Project Management: Strategies for Success"", ""AdditionalInfo"": { ""Example1$$String___skip"": ""test3"", ""Example2$$Int"": 3 }}
361
+ " ;
362
+
363
+ Func < object , string > generateId = ( x ) =>
364
+ {
365
+ if ( x is Location location )
366
+ {
367
+ return $ "Location-{ location . Name } ";
368
+ }
369
+ if ( x is Event ev )
370
+ {
371
+ return $ "Event-{ ev . Name } ";
372
+ }
373
+ throw new NotImplementedException ( ) ;
374
+
375
+ } ;
376
+
377
+ var jsonString = BuildExpextedContentJsonString < object > ( generateId , locationStockholm , locationLondon , event1 , event2 , event3 ) ;
378
+
379
+ var content = new StringContent ( expectedJsonString , Encoding . UTF8 , "application/json" ) ;
380
+
381
+ var response = new HttpResponseMessage ( HttpStatusCode . OK ) ;
382
+ var request = new HttpRequestMessage ( HttpMethod . Post , $ "/api/content/v2/data?id={ source } ") { Content = content } ;
383
+
384
+ mockRestClient . Setup ( c => c . SendAsync ( It . IsAny < HttpRequestMessage > ( ) ) ) . ReturnsAsync ( response ) ;
385
+ mockRestClient . Setup ( c => c . HandleResponse ( response ) ) ;
386
+
387
+ // Act
388
+ await repository . SaveContentAsync < object > ( generateId , locationStockholm , locationLondon , event1 , event2 , event3 ) ;
389
+
390
+ // Assert
391
+ Assert . AreEqual ( expectedJsonString , jsonString ) ;
392
+
393
+ mockRestClient . Verify ( c => c . SendAsync ( It . Is < HttpRequestMessage > ( x => Compare ( request , x ) ) ) , Times . Once ) ;
394
+ mockRestClient . Verify ( c => c . HandleResponse ( response ) , Times . Once ) ;
395
+ mockRestClient . VerifyAll ( ) ;
396
+ }
397
+
162
398
[ TestMethod ]
163
399
public async Task DeleteContentAsync_ThrowsNotImplementedException ( )
164
400
{
@@ -177,6 +413,7 @@ public async Task DeleteContentAsync_ThrowsNotImplementedException()
177
413
mockRestClient . VerifyAll ( ) ;
178
414
}
179
415
416
+
180
417
#region Private
181
418
private string BuildExpectedTypeJsonString ( )
182
419
{
@@ -192,7 +429,7 @@ private string BuildExpectedTypeJsonString()
192
429
return JsonSerializer . Serialize ( SourceConfigurationModel . GetTypeFieldConfiguration ( ) , serializeOptions ) ;
193
430
}
194
431
195
- private string BuildExpextedContentJsonString ( ExampleClassObject data )
432
+ private string BuildExpextedContentJsonString < T > ( Func < T , string > generateId , params T [ ] items )
196
433
{
197
434
var serializeOptions = new JsonSerializerOptions
198
435
{
@@ -205,11 +442,13 @@ private string BuildExpextedContentJsonString(ExampleClassObject data)
205
442
206
443
var itemJson = string . Empty ;
207
444
208
- itemJson += $ "{{ \" index\" : {{ \" _id\" : \" Optimizely.Graph.Source.Sdk.Tests.ExampleClassObject\" , \" language_routing\" : \" en\" }} }}";
209
- itemJson += Environment . NewLine ;
210
- itemJson += JsonSerializer . Serialize ( data , serializeOptions ) . Replace ( "\r \n " , "" ) ;
211
- itemJson += Environment . NewLine ;
212
-
445
+ foreach ( var data in items )
446
+ {
447
+ itemJson += $ "{{ \" index\" : {{ \" _id\" : \" { generateId ( data ) } \" , \" language_routing\" : \" en\" }} }}";
448
+ itemJson += Environment . NewLine ;
449
+ itemJson += JsonSerializer . Serialize ( data , serializeOptions ) . Replace ( "\r \n " , "" ) ;
450
+ itemJson += Environment . NewLine ;
451
+ }
213
452
return itemJson ;
214
453
}
215
454
0 commit comments