Skip to content

Commit 4e1b6c3

Browse files
committed
Merge branch 'main' into assorted-cleanup
2 parents bbbbb4a + 42643ca commit 4e1b6c3

26 files changed

Lines changed: 5790 additions & 2 deletions

.github/workflows/dotnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
- name: Build
5757
run: dotnet build --no-restore --configuration release
5858
- name: Test
59-
run: dotnet test --no-build --verbosity normal --configuration release --logger "trx;LogFileName=${{ matrix.platform }}-test-results.trx"
59+
run: dotnet test Kepware.Api.Test/Kepware.Api.Test.csproj --no-build --verbosity normal --configuration Release --logger "trx;LogFileName=${{ matrix.platform }}-test-results.trx"
6060
- name: Publish Test Report (${{ matrix.platform }})
6161
if: ${{ github.event_name == 'pull_request' }}
6262
uses: dorny/test-reporter@v1

Kepware-ConfigAPI-SDK-dotnet.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docfx", "docfx", "{EF3D2F75
5050
docs\docfx\toc.yml = docs\docfx\toc.yml
5151
EndProjectSection
5252
EndProject
53+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kepware.Api.TestIntg", "Kepware.Api.TestIntg\Kepware.Api.TestIntg.csproj", "{5FF0BFA8-5429-4823-9B18-05EB2E6779AE}"
54+
EndProject
5355
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{457CB96C-D60B-4994-B87C-BCDBF4035D58}"
5456
ProjectSection(SolutionItems) = preProject
5557
docs\docfx\docs\toc.yml = docs\docfx\docs\toc.yml
@@ -77,6 +79,10 @@ Global
7779
{E5F9DE9E-F9F2-4683-A7A9-ACE8501F7566}.Debug|Any CPU.Build.0 = Debug|Any CPU
7880
{E5F9DE9E-F9F2-4683-A7A9-ACE8501F7566}.Release|Any CPU.ActiveCfg = Release|Any CPU
7981
{E5F9DE9E-F9F2-4683-A7A9-ACE8501F7566}.Release|Any CPU.Build.0 = Release|Any CPU
82+
{5FF0BFA8-5429-4823-9B18-05EB2E6779AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
83+
{5FF0BFA8-5429-4823-9B18-05EB2E6779AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
84+
{5FF0BFA8-5429-4823-9B18-05EB2E6779AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
85+
{5FF0BFA8-5429-4823-9B18-05EB2E6779AE}.Release|Any CPU.Build.0 = Release|Any CPU
8086
EndGlobalSection
8187
GlobalSection(SolutionProperties) = preSolution
8288
HideSolutionNode = FALSE

Kepware.Api.Test/ApiClient/GetProductInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public async Task GetProductInfoAsync_ShouldReturnProductInfo_WhenApiRespondsSuc
3636

3737
#region GetProductInfoAsync - SupportsJsonProjectLoadService
3838

39+
//TODO: Add more test cases for TKS versions as well. Different product name
3940
[Theory]
4041
[InlineData("KEPServerEX", "12", 6, 17, true)] // Supports JSON Project Load Service (6.17+)
4142
[InlineData("KEPServerEX", "12", 6, 16, false)] // Does not support it (6.16)

Kepware.Api.Test/ApiClient/LoadEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ public async Task LoadEntityAsync_ShouldReturnNull_OnHttpRequestException()
196196
#endregion
197197

198198
#region LoadEntityAsync - Device with DynamicProperties
199-
199+
// TODO: Add these types of test for other entities (Device, TagGroup, Tag, etc.)
200200
[Fact]
201201
public async Task LoadEntityAsync_ShouldReturnDevice_WithCorrectDynamicProperties()
202202
{
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using Kepware.Api.Model;
2+
using Kepware.Api.Serializer;
3+
using Microsoft.Extensions.Logging;
4+
using Moq;
5+
using Moq.Contrib.HttpClient;
6+
using Shouldly;
7+
using System.Net;
8+
using System.Text.Json;
9+
using System.Threading.Tasks;
10+
using Xunit;
11+
using System.Net.Http.Json;
12+
using Kepware.Api.Model.Admin;
13+
14+
namespace Kepware.Api.TestIntg.ApiClient
15+
{
16+
public class AdminModelTests : TestApiClientBase
17+
{
18+
19+
#region GetAdminSettingsAsync Tests
20+
21+
[Fact]
22+
public async Task GetAdminSettingsAsync_ShouldReturnAdminSettings_WhenApiRespondsSuccessfully()
23+
{
24+
25+
// Act
26+
var result = await _kepwareApiClient.Admin.GetAdminSettingsAsync();
27+
28+
// Assert
29+
result.ShouldNotBeNull();
30+
result.EventLogConnectionPort.ShouldNotBe(default(int));
31+
result.EventLogMaxRecords.ShouldNotBe(default(int));
32+
if (_productInfo.ProductId == "013")
33+
{
34+
result.LicenseServer.ShouldNotBeNull();
35+
result.LicenseServer.RecheckIntervalMinutes.ShouldNotBe(default(int));
36+
result.LicenseServer.Enable.ShouldNotBeNull();
37+
}
38+
39+
}
40+
41+
[Fact]
42+
public async Task GetAdminSettingsAsync_ShouldReturnNull_WhenApiReturnsUnauthorized()
43+
{
44+
45+
// Act
46+
var result = await _badCredKepwareApiClient.Admin.GetAdminSettingsAsync();
47+
48+
// Assert
49+
result.ShouldBeNull();
50+
51+
}
52+
53+
#endregion
54+
55+
#region SetAdminSettingsAsync Tests
56+
57+
[Fact]
58+
public async Task SetAdminSettingsAsync_ShouldReturnTrue_WhenUpdateSuccessful()
59+
{
60+
// Arrange
61+
var newSettings = new AdminSettings();
62+
newSettings.EventLogMaxRecords = new Random().Next(10000, 30001);
63+
if (_productInfo.ProductId != "013")
64+
{
65+
newSettings.LicenseServer.Port = new Random().Next(10000, 30001);
66+
}
67+
68+
// Act
69+
var result = await _kepwareApiClient.Admin.SetAdminSettingsAsync(newSettings);
70+
71+
// Assert
72+
result.ShouldBeTrue();
73+
74+
}
75+
76+
[Fact]
77+
public async Task SetAdminSettingsAsync_ShouldReturnFalse_WhenUpdateFails()
78+
{
79+
// Arrange
80+
var newSettings = new AdminSettings();
81+
newSettings.EventLogConnectionPort = 1000;
82+
83+
84+
// Act
85+
var result = await _kepwareApiClient.Admin.SetAdminSettingsAsync(newSettings);
86+
87+
// Assert
88+
result.ShouldBeFalse();
89+
}
90+
91+
[Fact]
92+
public async Task SetAdminSettingsAsync_ShouldThrowException_WhenApiReturnsUnauthorized()
93+
{
94+
// Arrange
95+
var newSettings = new AdminSettings();
96+
newSettings.EventLogMaxRecords = new Random().Next(10000, 30001);
97+
98+
// Act and Assert
99+
await Should.ThrowAsync<InvalidOperationException>(async () =>
100+
{
101+
await _badCredKepwareApiClient.Admin.SetAdminSettingsAsync(newSettings);
102+
});
103+
104+
}
105+
106+
#endregion
107+
}
108+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
using Kepware.Api.Model;
2+
using Kepware.Api.Model.Services;
3+
using Moq;
4+
using Moq.Contrib.HttpClient;
5+
using Shouldly;
6+
using System;
7+
using System.Net;
8+
using System.Net.Http;
9+
using System.Text.Json;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Xunit;
13+
using Xunit.Extensions.Ordering;
14+
15+
namespace Kepware.Api.TestIntg.ApiClient
16+
{
17+
public class AutomaticTagGenerationAsyncTests : TestApiClientBase
18+
{
19+
private const string UNIT_TEST_CHANNEL = "unitTestChannel";
20+
private const string UNIT_TEST_DEVICE = "unitTestDevice";
21+
private const string ENDPOINT_TAG_GENERATION = $"/config/v1/project/channels/{UNIT_TEST_CHANNEL}/devices/{UNIT_TEST_DEVICE}/services/TagGeneration";
22+
private const string JOB_ENDPOINT = $"/config/v1/project/channels/{UNIT_TEST_CHANNEL}/devices/{UNIT_TEST_DEVICE}/services/TagGeneration/jobs/job123";
23+
24+
[Fact]
25+
public async Task AutomaticTagGenerationAsync_ShouldReturnKepServerJobPromise_WhenApiResponseIsInvalid()
26+
{
27+
// Arrange
28+
// Create channel that doesn't support ATG
29+
var channel = await AddTestChannel();
30+
var device = await AddTestDevice(channel);
31+
32+
// Act
33+
var result = await _kepwareApiClient.ApiServices.AutomaticTagGenerationAsync(channel.Name, device.Name, TimeSpan.FromSeconds(30));
34+
// Assert
35+
result.ShouldNotBeNull();
36+
//result.Endpoint.ShouldBe(ENDPOINT_TAG_GENERATION);
37+
result.JobTimeToLive.ShouldBe(TimeSpan.FromSeconds(30));
38+
39+
// Clean up
40+
await DeleteAllChannelsAsync();
41+
}
42+
43+
// [Fact]
44+
// public async Task AutomaticTagGenerationAsync_ShouldThrowException_WhenHttpClientThrowsException()
45+
// {
46+
// // Arrange
47+
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Put, $"{TEST_ENDPOINT}{ENDPOINT_TAG_GENERATION}")
48+
// .Throws(new HttpRequestException("Network error"));
49+
50+
// // Act & Assert
51+
// await Should.ThrowAsync<HttpRequestException>(async () =>
52+
// {
53+
// await _kepwareApiClient.ApiServices.AutomaticTagGenerationAsync(UNIT_TEST_CHANNEL, UNIT_TEST_DEVICE, TimeSpan.FromSeconds(30));
54+
// });
55+
// }
56+
57+
// [Fact]
58+
// public async Task AutomaticTagGenerationAsync_ShouldReturnSuccess_WhenJobCompletesSuccessfullyAfterFirstGet()
59+
// {
60+
// // Arrange
61+
// var jobResponse = new JobResponseMessage { ResponseStatusCode = (int)ApiResponseCode.Accepted, JobId = JOB_ENDPOINT };
62+
// var jobStatus = new JobStatusMessage { Completed = true };
63+
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Put, $"{TEST_ENDPOINT}{ENDPOINT_TAG_GENERATION}")
64+
// .ReturnsResponse(HttpStatusCode.Accepted, JsonSerializer.Serialize(jobResponse), "application/json");
65+
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, $"{TEST_ENDPOINT}{JOB_ENDPOINT}")
66+
// .ReturnsResponse(HttpStatusCode.OK, JsonSerializer.Serialize(jobStatus), "application/json");
67+
68+
// // Act
69+
// var result = await _kepwareApiClient.ApiServices.AutomaticTagGenerationAsync(UNIT_TEST_CHANNEL, UNIT_TEST_DEVICE, TimeSpan.FromSeconds(30));
70+
// var completionResult = await result.AwaitCompletionAsync();
71+
72+
// // Assert
73+
// completionResult.Value.ShouldBeTrue();
74+
// completionResult.IsSuccess.ShouldBeTrue();
75+
// }
76+
77+
[Fact]
78+
public async Task AutomaticTagGenerationAsync_ShouldReturnSuccess_WhenJobCompletesSuccessfully()
79+
{
80+
// Arrange
81+
var channel = await AddTestChannel(driver: "Allen-Bradley ControlLogix Ethernet");
82+
var device = await AddAtgTestDevice(channel);
83+
84+
// Act
85+
var result = await _kepwareApiClient.ApiServices.AutomaticTagGenerationAsync(channel.Name, device.Name, TimeSpan.FromSeconds(30));
86+
87+
// Assert
88+
result.ShouldNotBeNull();
89+
result.JobTimeToLive.ShouldBe(TimeSpan.FromSeconds(30));
90+
91+
// Wait for job completion
92+
var completionResult = await result.AwaitCompletionAsync();
93+
94+
// Assert
95+
completionResult.Value.ShouldBeTrue();
96+
completionResult.IsSuccess.ShouldBeTrue();
97+
98+
// Clean up
99+
await DeleteAllChannelsAsync();
100+
}
101+
102+
// [Fact]
103+
// public async Task AutomaticTagGenerationAsync_ShouldReturnFailure_WhenJobFailsAfterFirstGet()
104+
// {
105+
// // Arrange
106+
// var jobResponse = new JobResponseMessage { ResponseStatusCode = (int)ApiResponseCode.Accepted, JobId = JOB_ENDPOINT };
107+
// var jobStatus = new JobStatusMessage { Completed = false };
108+
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Put, $"{TEST_ENDPOINT}{ENDPOINT_TAG_GENERATION}")
109+
// .ReturnsResponse(HttpStatusCode.Accepted, JsonSerializer.Serialize(jobResponse), "application/json");
110+
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Get, $"{TEST_ENDPOINT}{JOB_ENDPOINT}")
111+
// .ReturnsResponse(HttpStatusCode.OK, JsonSerializer.Serialize(jobStatus), "application/json");
112+
113+
// // Act
114+
// var result = await _kepwareApiClient.ApiServices.AutomaticTagGenerationAsync(UNIT_TEST_CHANNEL, UNIT_TEST_DEVICE, TimeSpan.FromSeconds(1));
115+
// var completionResult = await result.AwaitCompletionAsync(TimeSpan.FromMilliseconds(100));
116+
117+
// // Assert
118+
// completionResult.Value.ShouldBeFalse();
119+
// completionResult.IsSuccess.ShouldBeFalse();
120+
// }
121+
122+
// [Fact]
123+
// public async Task AutomaticTagGenerationAsync_ShouldReturnFailure_WhenJobFailsAfterMultipleGets()
124+
// {
125+
// // Arrange
126+
// var jobResponse = new JobResponseMessage { ResponseStatusCode = (int)ApiResponseCode.Accepted, JobId = JOB_ENDPOINT };
127+
// var jobStatusIncomplete = new JobStatusMessage { Completed = false };
128+
129+
// var jobStatusFailed = new JobStatusMessage { Completed = true, Message = "Job failed" };
130+
131+
// _httpMessageHandlerMock.SetupRequest(HttpMethod.Put, $"{TEST_ENDPOINT}{ENDPOINT_TAG_GENERATION}")
132+
// .ReturnsResponse(HttpStatusCode.Accepted, JsonSerializer.Serialize(jobResponse), "application/json");
133+
// _httpMessageHandlerMock.SetupSequenceRequest(HttpMethod.Get, $"{TEST_ENDPOINT}{JOB_ENDPOINT}")
134+
// .ReturnsResponse(HttpStatusCode.OK, JsonSerializer.Serialize(jobStatusIncomplete), "application/json")
135+
// .ReturnsResponse(HttpStatusCode.OK, JsonSerializer.Serialize(jobStatusIncomplete), "application/json")
136+
// .ReturnsResponse(HttpStatusCode.ServiceUnavailable, JsonSerializer.Serialize(jobStatusFailed), "application/json");
137+
138+
// // Act
139+
// var result = await _kepwareApiClient.ApiServices.AutomaticTagGenerationAsync(UNIT_TEST_CHANNEL, UNIT_TEST_DEVICE, TimeSpan.FromSeconds(5));
140+
// var completionResult = await result.AwaitCompletionAsync(TimeSpan.FromMilliseconds(100));
141+
142+
// // Assert
143+
// completionResult.Value.ShouldBeFalse();
144+
// completionResult.IsSuccess.ShouldBeFalse();
145+
// }
146+
}
147+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Kepware.Api.Model;
2+
using Moq;
3+
using Moq.Contrib.HttpClient;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Net;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace Kepware.Api.TestIntg.ApiClient
12+
{
13+
public class GetProductInfo : TestApiClientBase
14+
{
15+
16+
[Fact]
17+
public async Task GetProductInfoAsync_ShouldReturnProductInfo_WhenApiRespondsSuccessfully()
18+
{
19+
20+
// Act
21+
var result = await _kepwareApiClient.GetProductInfoAsync();
22+
23+
// Assert
24+
Assert.NotNull(result);
25+
Assert.Equal(_productInfo.ProductId, result.ProductId);
26+
Assert.Equal(_productInfo.ProductName, result.ProductName);
27+
Assert.Equal(_productInfo.ProductVersion, result.ProductVersion);
28+
Assert.Equal(_productInfo.ProductVersionMajor, result.ProductVersionMajor);
29+
Assert.Equal(_productInfo.ProductVersionMinor, result.ProductVersionMinor);
30+
Assert.Equal(_productInfo.ProductVersionBuild, result.ProductVersionBuild);
31+
Assert.Equal(_productInfo.ProductVersionPatch, result.ProductVersionPatch);
32+
33+
}
34+
35+
}
36+
}

0 commit comments

Comments
 (0)