-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathProjectLoadTests.cs
More file actions
219 lines (181 loc) · 11.9 KB
/
ProjectLoadTests.cs
File metadata and controls
219 lines (181 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
using System;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Moq;
using Moq.Contrib.HttpClient;
using Microsoft.Extensions.Logging;
using Kepware.Api.Model;
using System.Linq;
using System.Collections.Generic;
using Kepware.Api.Serializer;
using Kepware.Api.Test.ApiClient;
using Kepware.Api.Util;
using Shouldly;
namespace Kepware.Api.Test.ApiClient
{
public class ProjectLoadTests : TestApiClientBase
{
private const string ENDPONT_FULL_PROJECT = "/config/v1/project?content=serialize";
private async Task ConfigureToServeFullProject()
{
var jsonData = await File.ReadAllTextAsync("_data/simdemo_en-us.json");
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + ENDPONT_FULL_PROJECT)
.ReturnsResponse(jsonData, "application/json");
}
private async Task ConfigureToServeEndpoints()
{
var projectData = await LoadJsonTestDataAsync();
var channels = projectData.Project?.Channels?.Select(c => new Channel { Name = c.Name, Description = c.Description, DynamicProperties = c.DynamicProperties }).ToList() ?? [];
// Serve project details
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + "/config/v1/project")
.ReturnsResponse(JsonSerializer.Serialize(new Project { Description = projectData?.Project?.Description, DynamicProperties = projectData?.Project?.DynamicProperties ?? [] }), "application/json");
// Serve channels without nested devices
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + "/config/v1/project/channels")
.ReturnsResponse(JsonSerializer.Serialize(channels), "application/json");
foreach (var channel in projectData?.Project?.Channels ?? [])
{
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + $"/config/v1/project/channels/{channel.Name}")
.ReturnsResponse(JsonSerializer.Serialize(new Channel { Name = channel.Name, Description = channel.Description, DynamicProperties = channel.DynamicProperties }), "application/json");
if (channel.Devices != null)
{
var devices = channel.Devices.Select(d => new Device { Name = d.Name, Description = d.Description, DynamicProperties = d.DynamicProperties }).ToList();
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, TEST_ENDPOINT + $"/config/v1/project/channels/{channel.Name}/devices")
.ReturnsResponse(JsonSerializer.Serialize(devices), "application/json");
foreach (var device in channel.Devices)
{
var deviceEndpoint = TEST_ENDPOINT + $"/config/v1/project/channels/{channel.Name}/devices/{device.Name}";
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, deviceEndpoint)
.ReturnsResponse(JsonSerializer.Serialize(new Device { Name = device.Name, Description = device.Description, DynamicProperties = device.DynamicProperties }), "application/json");
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, deviceEndpoint + "/tags")
.ReturnsResponse(JsonSerializer.Serialize(device.Tags), "application/json");
ConfigureToServeEndpointsTagGroupsRecursive(deviceEndpoint, device.TagGroups ?? []);
}
}
}
}
private void ConfigureToServeEndpointsTagGroupsRecursive(string endpoint, IEnumerable<DeviceTagGroup> tagGroups)
{
var tagGroupEndpoint = endpoint + "/tag_groups";
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, tagGroupEndpoint)
.ReturnsResponse(JsonSerializer.Serialize(tagGroups), "application/json");
foreach (var tagGroup in tagGroups)
{
_httpMessageHandlerMock.SetupRequest(HttpMethod.Get, string.Concat(tagGroupEndpoint, "/", tagGroup.Name, "/tags"))
.ReturnsResponse(JsonSerializer.Serialize(tagGroup.Tags), "application/json");
ConfigureToServeEndpointsTagGroupsRecursive(string.Concat(tagGroupEndpoint, "/", tagGroup.Name), tagGroup.TagGroups ?? []);
}
}
[Theory]
[InlineData("KEPServerEX", "12", 6, 17, true)]
[InlineData("KEPServerEX", "12", 6, 16, false)]
[InlineData("ThingWorxKepwareEdge", "13", 1, 10, true)]
[InlineData("ThingWorxKepwareEdge", "13", 1, 9, false)]
[InlineData("UnknownProduct", "99", 10, 0, false)]
public async Task LoadProject_ShouldLoadCorrectly_BasedOnProductSupport(
string productName, string productId, int majorVersion, int minorVersion, bool supportsJsonLoad)
{
ConfigureConnectedClient(productName, productId, majorVersion, minorVersion);
if (supportsJsonLoad)
{
await ConfigureToServeFullProject();
}
else
{
await ConfigureToServeEndpoints();
}
var project = await _kepwareApiClient.Project.LoadProject(true);
project.IsLoadedByProjectLoadService.ShouldBe(supportsJsonLoad);
project.ShouldNotBeNull();
project.Channels.ShouldNotBeEmpty("Channels list should not be empty.");
var testProject = await LoadJsonTestDataAsync();
var compareResult = EntityCompare.Compare<ChannelCollection, Channel>(testProject?.Project?.Channels, project?.Channels);
compareResult.ShouldNotBeNull();
compareResult.UnchangedItems.ShouldNotBeEmpty("All channels should be unchanged.");
compareResult.ChangedItems.ShouldBeEmpty("No channels should be changed.");
compareResult.ItemsOnlyInLeft.ShouldBeEmpty("No channels should exist only in the test data.");
compareResult.ItemsOnlyInRight.ShouldBeEmpty("No channels should exist only in the loaded project.");
foreach (var (ExpectedChannel, LoadedChannel) in testProject?.Project?.Channels?.Zip(project?.Channels ?? []) ?? [])
{
var deviceCompareResult = EntityCompare.Compare<DeviceCollection, Device>(ExpectedChannel.Devices, LoadedChannel.Devices);
deviceCompareResult.ShouldNotBeNull();
deviceCompareResult.UnchangedItems.ShouldNotBeEmpty($"All devices in channel {ExpectedChannel.Name} should be unchanged.");
deviceCompareResult.ChangedItems.ShouldBeEmpty($"No devices in channel {ExpectedChannel.Name} should be changed.");
deviceCompareResult.ItemsOnlyInLeft.ShouldBeEmpty($"No devices should exist only in the test data for channel {ExpectedChannel.Name}.");
deviceCompareResult.ItemsOnlyInRight.ShouldBeEmpty($"No devices should exist only in the loaded project for channel {ExpectedChannel.Name}.");
foreach (var (ExpectedDevice, LoadedDevice) in ExpectedChannel.Devices?.Zip(LoadedChannel.Devices ?? []) ?? [])
{
if (ExpectedDevice.Tags?.Count > 0 || LoadedDevice.Tags?.Count > 0)
{
var tagCompareResult = EntityCompare.Compare<DeviceTagCollection, Tag>(ExpectedDevice.Tags, LoadedDevice.Tags);
tagCompareResult.ShouldNotBeNull();
tagCompareResult.UnchangedItems.ShouldNotBeEmpty($"All tags in device {ExpectedDevice.Name} should be unchanged.");
tagCompareResult.ChangedItems.ShouldBeEmpty($"No tags in device {ExpectedDevice.Name} should be changed.");
tagCompareResult.ItemsOnlyInLeft.ShouldBeEmpty($"No tags should exist only in the test data for device {ExpectedDevice.Name}.");
tagCompareResult.ItemsOnlyInRight.ShouldBeEmpty($"No tags should exist only in the loaded project for device {ExpectedDevice.Name}.");
}
CompareTagGroupsRecursive(ExpectedDevice.TagGroups, LoadedDevice.TagGroups, ExpectedDevice.Name);
}
}
}
private static void CompareTagGroupsRecursive(DeviceTagGroupCollection? expected, DeviceTagGroupCollection? actual, string parentName)
{
if ((expected?.Count ?? 0) == 0 && (actual?.Count ?? 0) == 0)
return;
var tagGroupCompareResult = EntityCompare.Compare<DeviceTagGroupCollection, DeviceTagGroup>(expected, actual);
tagGroupCompareResult.ShouldNotBeNull();
tagGroupCompareResult.UnchangedItems.ShouldNotBeEmpty($"All tag groups in {parentName} should be unchanged.");
tagGroupCompareResult.ChangedItems.ShouldBeEmpty($"No tag groups in {parentName} should be changed.");
tagGroupCompareResult.ItemsOnlyInLeft.ShouldBeEmpty($"No tag groups should exist only in the test data for {parentName}.");
tagGroupCompareResult.ItemsOnlyInRight.ShouldBeEmpty($"No tag groups should exist only in the loaded project for {parentName}.");
foreach (var (ExpectedTagGroup, ActualTagGroup) in expected?.Zip(actual ?? []) ?? [])
{
var thisName = parentName + "/" + ExpectedTagGroup.Name;
if (ExpectedTagGroup.Tags?.Count > 0 || ActualTagGroup.Tags?.Count > 0)
{
var tagCompareResult = EntityCompare.Compare<DeviceTagCollection, Tag>(ExpectedTagGroup.Tags, ExpectedTagGroup.Tags);
tagCompareResult.ShouldNotBeNull();
tagCompareResult.UnchangedItems.ShouldNotBeEmpty($"All tags in device {thisName} should be unchanged.");
tagCompareResult.ChangedItems.ShouldBeEmpty($"No tags in device {thisName} should be changed.");
tagCompareResult.ItemsOnlyInLeft.ShouldBeEmpty($"No tags should exist only in the test data for device {thisName}.");
tagCompareResult.ItemsOnlyInRight.ShouldBeEmpty($"No tags should exist only in the loaded project for device {thisName}.");
}
CompareTagGroupsRecursive(ExpectedTagGroup.TagGroups, ActualTagGroup.TagGroups, thisName);
}
}
[Theory]
[InlineData("KEPServerEX", "12", 6, 17)]
[InlineData("KEPServerEX", "12", 6, 16)]
[InlineData("ThingWorxKepwareEdge", "13", 1, 10)]
[InlineData("ThingWorxKepwareEdge", "13", 1, 9)]
[InlineData("UnknownProduct", "99", 10, 0)]
public async Task LoadProject_NotFull_ShouldLoadCorrectly_BasedOnProductSupport(
string productName, string productId, int majorVersion, int minorVersion)
{
ConfigureConnectedClient(productName, productId, majorVersion, minorVersion);
await ConfigureToServeEndpoints();
var project = await _kepwareApiClient.Project.LoadProject(blnLoadFullProject: false);
project.ShouldNotBeNull();
project.Channels.ShouldBeNull("Channels list should be null.");
foreach (var channel in project.Channels ?? [])
{
channel.Devices.ShouldBeNull("Devices should not be loaded when not requested.");
}
}
[Fact]
public async Task LoadProject_ShouldReturnEmptyProject_WhenHttpRequestFails()
{
// Arrange
_httpMessageHandlerMock.SetupAnyRequest()
.ThrowsAsync(new HttpRequestException());
// Act
var project = await _kepwareApiClient.Project.LoadProject(true);
// Assert
project.ShouldNotBeNull();
project.Channels.ShouldBeNull();
}
}
}