Skip to content

Commit 7c60442

Browse files
committed
feat(api): extended optimized recursion ProjectLoad to tag groups
1 parent b178ba2 commit 7c60442

19 files changed

Lines changed: 7266 additions & 81 deletions

Kepware.Api.Test/ApiClient/ProjectLoadTests.cs

Lines changed: 26 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -22,63 +22,6 @@ namespace Kepware.Api.Test.ApiClient
2222
public class ProjectLoadTests : TestApiClientBase
2323
{
2424

25-
//private async Task ConfigureToServeEndpoints()
26-
//{
27-
// var projectData = await LoadJsonTestDataAsync();
28-
29-
// var channels = projectData.Project?.Channels?.Select(c => new Channel { Name = c.Name, Description = c.Description, DynamicProperties = c.DynamicProperties }).ToList() ?? [];
30-
31-
// // Serve project details
32-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + "/config/v1/project")
33-
// .ReturnsResponse(JsonSerializer.Serialize(new Project { Description = projectData?.Project?.Description, DynamicProperties = projectData?.Project?.DynamicProperties ?? [] }), "application/json");
34-
35-
// // Serve channels without nested devices
36-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + "/config/v1/project/channels")
37-
// .ReturnsResponse(JsonSerializer.Serialize(channels), "application/json");
38-
39-
// foreach (var channel in projectData?.Project?.Channels ?? [])
40-
// {
41-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + $"/config/v1/project/channels/{channel.Name}")
42-
// .ReturnsResponse(JsonSerializer.Serialize(new Channel { Name = channel.Name, Description = channel.Description, DynamicProperties = channel.DynamicProperties }), "application/json");
43-
44-
// if (channel.Devices != null)
45-
// {
46-
// var devices = channel.Devices.Select(d => new Device { Name = d.Name, Description = d.Description, DynamicProperties = d.DynamicProperties }).ToList();
47-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + $"/config/v1/project/channels/{channel.Name}/devices")
48-
// .ReturnsResponse(JsonSerializer.Serialize(devices), "application/json");
49-
50-
// foreach (var device in channel.Devices)
51-
// {
52-
// var deviceEndpoint = TEST_ENDPOINT + $"/config/v1/project/channels/{channel.Name}/devices/{device.Name}";
53-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, deviceEndpoint)
54-
// .ReturnsResponse(JsonSerializer.Serialize(new Device { Name = device.Name, Description = device.Description, DynamicProperties = device.DynamicProperties }), "application/json");
55-
56-
57-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, deviceEndpoint + "/tags")
58-
// .ReturnsResponse(JsonSerializer.Serialize(device.Tags), "application/json");
59-
60-
// ConfigureToServeEndpointsTagGroupsRecursive(deviceEndpoint, device.TagGroups ?? []);
61-
// }
62-
// }
63-
// }
64-
//}
65-
66-
//private void ConfigureToServeEndpointsTagGroupsRecursive(string endpoint, IEnumerable<DeviceTagGroup> tagGroups)
67-
//{
68-
// var tagGroupEndpoint = endpoint + "/tag_groups";
69-
70-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, tagGroupEndpoint)
71-
// .ReturnsResponse(JsonSerializer.Serialize(tagGroups), "application/json");
72-
73-
// foreach (var tagGroup in tagGroups)
74-
// {
75-
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, string.Concat(tagGroupEndpoint, "/", tagGroup.Name, "/tags"))
76-
// .ReturnsResponse(JsonSerializer.Serialize(tagGroup.Tags), "application/json");
77-
78-
// ConfigureToServeEndpointsTagGroupsRecursive(string.Concat(tagGroupEndpoint, "/", tagGroup.Name), tagGroup.TagGroups ?? []);
79-
// }
80-
//}
81-
8225
[Theory]
8326
[InlineData("KEPServerEX", "12", 6, 17, true)]
8427
[InlineData("KEPServerEX", "12", 6, 16, false)]
@@ -88,6 +31,12 @@ public class ProjectLoadTests : TestApiClientBase
8831
public async Task LoadProject_ShouldLoadCorrectly_BasedOnProductSupport(
8932
string productName, string productId, int majorVersion, int minorVersion, bool supportsJsonLoad)
9033
{
34+
// This test will validate that the LoadProjectAsync method correctly loads the project structure and
35+
// content based on whether the connected server version supports JsonProjectLoad. It will compare the loaded project against expected test data to ensure accuracy.
36+
// For servers that support JsonProjectLoad, the test will configure the mock server to serve a full JSON project
37+
// and validate that the loaded project matches the test data exactly.
38+
39+
// Arrange
9140
ConfigureConnectedClient(productName, productId, majorVersion, minorVersion);
9241

9342
if (supportsJsonLoad)
@@ -99,8 +48,10 @@ public async Task LoadProject_ShouldLoadCorrectly_BasedOnProductSupport(
9948
await ConfigureToServeEndpoints();
10049
}
10150

51+
// Act
10252
var project = await _kepwareApiClient.Project.LoadProjectAsync(blnLoadFullProject: true);
10353

54+
// Assert
10455
project.IsLoadedByProjectLoadService.ShouldBe(supportsJsonLoad);
10556

10657
project.ShouldNotBeNull();
@@ -149,6 +100,11 @@ public async Task LoadProject_ShouldLoadCorrectly_BasedOnProductSupport(
149100
public async Task LoadProject_ShouldLoadCorrectly_Serialize_BasedOnProductSupport(
150101
string productName, string productId, int majorVersion, int minorVersion, bool supportsJsonLoad)
151102
{
103+
// This test will validate that the LoadProjectAsync method correctly loads the project structure using the optimized recursion method.
104+
// It will compare the loaded project against expected test data to ensure accuracy. The test will configure the mock server to serve
105+
// endpoints to support an optimized recursion load and validate that the loaded project matches the test data exactly.
106+
107+
// Arrange
152108
ConfigureConnectedClient(productName, productId, majorVersion, minorVersion);
153109

154110
if (supportsJsonLoad)
@@ -161,10 +117,16 @@ public async Task LoadProject_ShouldLoadCorrectly_Serialize_BasedOnProductSuppor
161117
throw SkipException.ForSkip($"Product {productName} v{majorVersion}.{minorVersion} (id={productId}) does not support JSON project load. Skipping full-project test case.");
162118
}
163119

164-
var tagLimitOverride = 100; // Set a high tag limit to ensure all tags are loaded for comparison
120+
// Override the tag limit to ensure that we are testing the optimized recursion and selectively load objects based on the tag limit.
121+
// See _data/simdemo_en.json and json chunks in _data/projectLoadSerializeData for data that is served by the mock server for this test.
122+
var tagLimitOverride = 100;
123+
165124

125+
// Act
166126
var project = await _kepwareApiClient.Project.LoadProjectAsync(blnLoadFullProject: true, projectLoadTagLimit: tagLimitOverride);
167127

128+
129+
// Assert
168130
// Optimized recursion is done for this test, which will result in false.
169131
project.IsLoadedByProjectLoadService.ShouldBeFalse();
170132

@@ -204,6 +166,12 @@ public async Task LoadProject_ShouldLoadCorrectly_Serialize_BasedOnProductSuppor
204166
CompareTagGroupsRecursive(ExpectedDevice.TagGroups, LoadedDevice.TagGroups, ExpectedDevice.Name);
205167
}
206168
}
169+
170+
// Verify expected number of calls to the project load endpoints to ensure that the optimized recursion is selectively loading objects based on the tag limit.
171+
foreach (var uri in _optimizedRecursionUris)
172+
{
173+
_httpMessageHandlerMock.VerifyRequest(HttpMethod.Get, uri);
174+
}
207175
}
208176

209177
private static void CompareTagGroupsRecursive(DeviceTagGroupCollection? expected, DeviceTagGroupCollection? actual, string parentName)

0 commit comments

Comments
 (0)