From 1d6a2db8ce23186e7ae117c45a8b9916661ab831 Mon Sep 17 00:00:00 2001 From: jakeminard Date: Thu, 11 Sep 2025 15:05:04 -0400 Subject: [PATCH 1/2] Serialize api response to response object to return journal id. --- .../GraphSourceRepositoryTests.cs | 62 ++++++++++++++++--- .../Repositories/GraphSourceRepository.cs | 14 ++--- .../Repositories/Models/ApiResponse.cs | 4 ++ 3 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs diff --git a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs index 86e350a..e049747 100644 --- a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs +++ b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs @@ -203,14 +203,62 @@ public async Task SaveContentAsync_SerializesData_AndCallsGraphClient() var request = new HttpRequestMessage(HttpMethod.Post, $"/api/content/v2/data?id={source}") { Content = content }; mockRestClient.Setup(c => c.SendAsync(It.IsAny())).ReturnsAsync(response); - mockRestClient.Setup(c => c.HandleResponse(response)); + mockRestClient.Setup(c => c.HandleResponse(response)); // Act await repository.SaveContentAsync(generateId: (x) => x.ToString(), exampleData); // Assert mockRestClient.Verify(c => c.SendAsync(It.Is(x => Compare(request, x))), Times.Once); - mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); + mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); + mockRestClient.VerifyAll(); + } + + [TestMethod] + public async Task SaveContentAsync_SerializesData_ReturnsJournalId() + { + // Arrange + repository.ConfigureContentType() + .Field(x => x.FirstName, IndexingType.Searchable) + .Field(x => x.LastName, IndexingType.Searchable) + .Field(x => x.Age, IndexingType.Queryable) + .Field(x => x.SubType, IndexingType.PropertyType); + + repository.ConfigurePropertyType() + .Field(x => x.One, IndexingType.Searchable) + .Field(x => x.Two, IndexingType.Queryable); + + var exampleData = new ExampleClassObject + { + FirstName = "First", + LastName = "Last", + Age = 99, + SubType = new ExampleClassObject.SubType1 + { + One = "one", + Two = 13 + } + }; + + var expectedJsonString = BuildExpectedContentJsonString(x => x.ToString(), exampleData); + + var content = new StringContent(expectedJsonString, Encoding.UTF8, "application/json"); + + var response = new HttpResponseMessage(HttpStatusCode.OK); + var request = new HttpRequestMessage(HttpMethod.Post, $"/api/content/v2/data?id={source}") { Content = content }; + + var expectedApiResponse = new ApiResponse { JournalId = "stream/id" }; + + mockRestClient.Setup(c => c.SendAsync(It.IsAny())).ReturnsAsync(response); + mockRestClient.Setup(c => c.HandleResponse(response)).ReturnsAsync(expectedApiResponse); + + // Act + var actualJournalId = await repository.SaveContentAsync(generateId: (x) => x.ToString(), exampleData); + + // Assert + Assert.AreEqual(expectedApiResponse.JournalId, actualJournalId); + mockRestClient.Verify(c => c.SendAsync(It.Is(x => Compare(request, x))), Times.Once); + mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); mockRestClient.VerifyAll(); } @@ -284,11 +332,11 @@ public async Task SaveContentAsync_WithMultipleTypes_ShouldGenerateJsonForConten {""index"":{""_id"":""Location-London"",""language_routing"":""en""}} {""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""} {""index"":{""_id"":""Event-Future of Project Management"",""language_routing"":""en""}} -{""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}} +{""Status$$String"":""Published"",""__typename"":""Event"",""_rbac"":""r:Everyone:Read"",""ContentType$$String"":[""Event""],""Language"":{""Name$$String"":""en""},""LocationName$$String"":""Stockholm"",""Time$$DateTime"":""2024-10-22T04:00:00Z"",""Name$$String___searchable"":""Future of Project Management"",""AdditionalInfo"":{""Example1$$String___skip"":""test1"",""Example2$$Int"":1}} {""index"":{""_id"":""Event-Week of Hope: Football Camp for Homeless Children in Hanoi!"",""language_routing"":""en""}} -{""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}} +{""Status$$String"":""Published"",""__typename"":""Event"",""_rbac"":""r:Everyone:Read"",""ContentType$$String"":[""Event""],""Language"":{""Name$$String"":""en""},""LocationName$$String"":""Hanoi"",""Time$$DateTime"":""2024-10-27T04:00:00Z"",""Name$$String___searchable"":""Week of Hope: Football Camp for Homeless Children in Hanoi!"",""AdditionalInfo"":{""Example1$$String___skip"":""test2"",""Example2$$Int"":2}} {""index"":{""_id"":""Event-Optimizing Project Management: Strategies for Success"",""language_routing"":""en""}} -{""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}} +{""Status$$String"":""Published"",""__typename"":""Event"",""_rbac"":""r:Everyone:Read"",""ContentType$$String"":[""Event""],""Language"":{""Name$$String"":""en""},""LocationName$$String"":""London"",""Time$$DateTime"":""2024-11-03T04:00:00Z"",""Name$$String___searchable"":""Optimizing Project Management: Strategies for Success"",""AdditionalInfo"":{""Example1$$String___skip"":""test3"",""Example2$$Int"":3}} "; Func generateId = (x) => @@ -313,7 +361,7 @@ public async Task SaveContentAsync_WithMultipleTypes_ShouldGenerateJsonForConten var request = new HttpRequestMessage(HttpMethod.Post, $"/api/content/v2/data?id={source}") { Content = content }; mockRestClient.Setup(c => c.SendAsync(It.IsAny())).ReturnsAsync(response); - mockRestClient.Setup(c => c.HandleResponse(response)); + mockRestClient.Setup(c => c.HandleResponse(response)); // Act await repository.SaveContentAsync(generateId, locationStockholm, locationLondon, event1, event2, event3); @@ -322,7 +370,7 @@ public async Task SaveContentAsync_WithMultipleTypes_ShouldGenerateJsonForConten Assert.AreEqual(expectedJsonString, jsonString); mockRestClient.Verify(c => c.SendAsync(It.Is(x => Compare(request, x))), Times.Once); - mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); + mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); mockRestClient.VerifyAll(); } diff --git a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs index 594a0ef..9ff2f02 100644 --- a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs +++ b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs @@ -85,15 +85,11 @@ public async Task SaveContentAsync(Func generateId, params { var content = CreateContent(generateId, data); - using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"{DataUrl}?id={source}")) - { - requestMessage.Content = content; - using (var responseMessage = await client.SendAsync(requestMessage)) - { - await client.HandleResponse(responseMessage); - } - } - return string.Empty; + using var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"{DataUrl}?id={source}"); + requestMessage.Content = content; + using var responseMessage = await client.SendAsync(requestMessage); + var response = await client.HandleResponse(responseMessage); + return response?.JournalId ?? string.Empty; } public StringContent CreateContent(Func generateId, params T[] data) diff --git a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs new file mode 100644 index 0000000..dc829df --- /dev/null +++ b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs @@ -0,0 +1,4 @@ +public class ApiResponse +{ + public string JournalId { get; set; } +} \ No newline at end of file From c083f7690dd1e7caede0cb3781494dfa84a63379 Mon Sep 17 00:00:00 2001 From: jakeminard Date: Thu, 11 Sep 2025 15:08:33 -0400 Subject: [PATCH 2/2] Rename response object class. --- .../RepositoryTests/GraphSourceRepositoryTests.cs | 14 +++++++------- .../Repositories/GraphSourceRepository.cs | 2 +- .../{ApiResponse.cs => ContentV2ApiResponse.cs} | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) rename Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/{ApiResponse.cs => ContentV2ApiResponse.cs} (59%) diff --git a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs index e049747..4009a4f 100644 --- a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs +++ b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk.Tests/RepositoryTests/GraphSourceRepositoryTests.cs @@ -203,14 +203,14 @@ public async Task SaveContentAsync_SerializesData_AndCallsGraphClient() var request = new HttpRequestMessage(HttpMethod.Post, $"/api/content/v2/data?id={source}") { Content = content }; mockRestClient.Setup(c => c.SendAsync(It.IsAny())).ReturnsAsync(response); - mockRestClient.Setup(c => c.HandleResponse(response)); + mockRestClient.Setup(c => c.HandleResponse(response)); // Act await repository.SaveContentAsync(generateId: (x) => x.ToString(), exampleData); // Assert mockRestClient.Verify(c => c.SendAsync(It.Is(x => Compare(request, x))), Times.Once); - mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); + mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); mockRestClient.VerifyAll(); } @@ -247,10 +247,10 @@ public async Task SaveContentAsync_SerializesData_ReturnsJournalId() var response = new HttpResponseMessage(HttpStatusCode.OK); var request = new HttpRequestMessage(HttpMethod.Post, $"/api/content/v2/data?id={source}") { Content = content }; - var expectedApiResponse = new ApiResponse { JournalId = "stream/id" }; + var expectedApiResponse = new ContentV2ApiResponse { JournalId = "stream/id" }; mockRestClient.Setup(c => c.SendAsync(It.IsAny())).ReturnsAsync(response); - mockRestClient.Setup(c => c.HandleResponse(response)).ReturnsAsync(expectedApiResponse); + mockRestClient.Setup(c => c.HandleResponse(response)).ReturnsAsync(expectedApiResponse); // Act var actualJournalId = await repository.SaveContentAsync(generateId: (x) => x.ToString(), exampleData); @@ -258,7 +258,7 @@ public async Task SaveContentAsync_SerializesData_ReturnsJournalId() // Assert Assert.AreEqual(expectedApiResponse.JournalId, actualJournalId); mockRestClient.Verify(c => c.SendAsync(It.Is(x => Compare(request, x))), Times.Once); - mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); + mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); mockRestClient.VerifyAll(); } @@ -361,7 +361,7 @@ public async Task SaveContentAsync_WithMultipleTypes_ShouldGenerateJsonForConten var request = new HttpRequestMessage(HttpMethod.Post, $"/api/content/v2/data?id={source}") { Content = content }; mockRestClient.Setup(c => c.SendAsync(It.IsAny())).ReturnsAsync(response); - mockRestClient.Setup(c => c.HandleResponse(response)); + mockRestClient.Setup(c => c.HandleResponse(response)); // Act await repository.SaveContentAsync(generateId, locationStockholm, locationLondon, event1, event2, event3); @@ -370,7 +370,7 @@ public async Task SaveContentAsync_WithMultipleTypes_ShouldGenerateJsonForConten Assert.AreEqual(expectedJsonString, jsonString); mockRestClient.Verify(c => c.SendAsync(It.Is(x => Compare(request, x))), Times.Once); - mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); + mockRestClient.Verify(c => c.HandleResponse(response), Times.Once); mockRestClient.VerifyAll(); } diff --git a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs index 9ff2f02..cd82dd8 100644 --- a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs +++ b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/GraphSourceRepository.cs @@ -88,7 +88,7 @@ public async Task SaveContentAsync(Func generateId, params using var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"{DataUrl}?id={source}"); requestMessage.Content = content; using var responseMessage = await client.SendAsync(requestMessage); - var response = await client.HandleResponse(responseMessage); + var response = await client.HandleResponse(responseMessage); return response?.JournalId ?? string.Empty; } diff --git a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ContentV2ApiResponse.cs similarity index 59% rename from Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs rename to Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ContentV2ApiResponse.cs index dc829df..5f92fb3 100644 --- a/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ApiResponse.cs +++ b/Optimizely.Graph.Source.Sdk/Optimizely.Graph.Source.Sdk/Repositories/Models/ContentV2ApiResponse.cs @@ -1,4 +1,4 @@ -public class ApiResponse +public class ContentV2ApiResponse { public string JournalId { get; set; } } \ No newline at end of file