From 0ac034682d625dba49770dfe9a067f47bac426b4 Mon Sep 17 00:00:00 2001 From: lordmilko Date: Wed, 25 Nov 2020 11:10:44 +1100 Subject: [PATCH] -Improve integration test reliability -Improve Get-SensorHistory unit test reliability when real time time differences cause one second errors in expected vs actual API request URLs -Fix Uninstall-GoPrtgServer tests failing on Linux PowerShell Core due to new error message when command is not found --- .../PrtgClientConnectionTests.cs | 37 ++++++++--- .../CSharp/ObjectData/Query/FilterTests.cs | 38 ++++++----- .../ObjectManipulation/AddObjectTests.cs | 2 +- .../CSharp/ObjectManipulation/StateTests.cs | 30 ++++++++- .../ObjectData/Get-SensorTarget.Tests.ps1 | 2 +- .../Set-ObjectProperty.Container.Tests.ps1 | 4 +- .../ObjectManipulation/Pause-Object.Tests.ps1 | 4 +- .../PrtgAPI.Tests.IntegrationTests.csproj | 1 + .../Support/ServerManager.cs | 16 ++--- .../Support/ServiceControllerExtensions.cs | 62 ++++++++++++++++++ .../GoPrtg/Uninstall-GoPrtgServer.Tests.ps1 | 4 +- .../ObjectData/Get-SensorHistory.Tests.ps1 | 35 +++++++--- .../TestResponses/AddressValidatorResponse.cs | 40 ++++++++++- .../Enums/Serialization/SensorTypeInternal.cs | Bin 127190 -> 137876 bytes src/PrtgAPI/Request/ResponseParser.cs | 10 +-- src/PrtgAPI/Utilities/StringExtensions.cs | 2 +- 16 files changed, 228 insertions(+), 59 deletions(-) create mode 100644 src/PrtgAPI.Tests.IntegrationTests/Support/ServiceControllerExtensions.cs diff --git a/src/PrtgAPI.Tests.IntegrationTests/CSharp/Infrastructure/PrtgClientConnectionTests.cs b/src/PrtgAPI.Tests.IntegrationTests/CSharp/Infrastructure/PrtgClientConnectionTests.cs index 483c5ec6..f66efacc 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/CSharp/Infrastructure/PrtgClientConnectionTests.cs +++ b/src/PrtgAPI.Tests.IntegrationTests/CSharp/Infrastructure/PrtgClientConnectionTests.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using PrtgAPI.Parameters; +using PrtgAPI.Tests.IntegrationTests.Support; using PrtgAPI.Tests.UnitTests.Support; namespace PrtgAPI.Tests.IntegrationTests.Infrastructure @@ -223,18 +224,18 @@ private void Logic_Client_RetryRequestInternal(Action action, bool i var localClient = new PrtgClient(Settings.ServerWithProto, Settings.UserName, Settings.Password); localClient.RetryRequest += (sender, args) => { - Logger.LogTestDetail($"Handling retry {retriesMade + 1}"); + retriesMade++; + + Logger.LogTestDetail($"Handling retry {retriesMade}"); if (!isAsync) AssertEx.AreEqual(initialThread, Thread.CurrentThread.ManagedThreadId, "Event was not handled on initial thread"); - retriesMade++; }; localClient.RetryCount = retriesToMake; Logger.LogTestDetail("Stopping PRTG Service"); - coreService.Stop(); - coreService.WaitForStatus(ServiceControllerStatus.Stopped); + coreService.StopAndWaitForStatus(ServiceControllerStatus.Stopped); try { @@ -251,11 +252,31 @@ private void Logic_Client_RetryRequestInternal(Action action, bool i finally { Logger.LogTestDetail("Starting PRTG Service"); - coreService.Start(); - coreService.WaitForStatus(ServiceControllerStatus.Running); + coreService.StartAndWaitForStatus(ServiceControllerStatus.Running); + + var time = 90; + + while (true) + { + try + { + var probe = client.GetProbes(); + + break; + } + catch (HttpRequestException) + { + var duration = 5; + + time -= duration; + + if (time < 0) + throw; - Logger.LogTestDetail("Sleeping for 30 seconds"); - Thread.Sleep(30000); + Logger.LogTestDetail($"Sleeping for {duration} seconds as service is not up"); + Thread.Sleep(duration * 1000); + } + } Logger.LogTestDetail("Refreshing and sleeping for 20 seconds"); localClient.RefreshObject(Settings.Device); diff --git a/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectData/Query/FilterTests.cs b/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectData/Query/FilterTests.cs index 88ccc145..9632a59f 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectData/Query/FilterTests.cs +++ b/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectData/Query/FilterTests.cs @@ -1145,11 +1145,13 @@ public void Data_QueryFilter_SensorProperties_Downtime_NotEquals() [TestMethod] [IntegrationTest] - public void Data_QueryFilter_SensorProperties_Downtime_GreaterThan() + public void Data_QueryFilter_SensorProperties_Downtime_GreaterThan_bad() { var downSensor = client.GetSensor(Settings.DownSensor); - ExecuteSensor(s => s.Downtime > downSensor.Downtime, Property.Downtime, downSensor.Downtime, FilterOperator.GreaterThan); + var expectedDowntime = downSensor.Downtime - 10; + + ExecuteSensor(s => s.Downtime > expectedDowntime, Property.Downtime, expectedDowntime, FilterOperator.GreaterThan); } [TestMethod] @@ -1534,7 +1536,7 @@ public void Data_QueryFilter_SensorProperties_TotalMonitorTime_Equals() { var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime; - Assert.IsNotNull(monitorTime); + Assert.IsTrue(monitorTime.TotalSeconds >= 0, "Cannot test TotalMonitorTime if TotalSeconds value is 0"); ExecuteSensor(s => s.TotalMonitorTime == monitorTime, Property.TotalMonitorTime, monitorTime); } @@ -1545,7 +1547,7 @@ public void Data_QueryFilter_SensorProperties_TotalMonitorTime_NotEquals() { var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime; - Assert.IsNotNull(monitorTime); + Assert.IsTrue(monitorTime.TotalSeconds >= 0, "Cannot test TotalMonitorTime if TotalSeconds value is 0"); ExecuteSensor(s => s.TotalMonitorTime != monitorTime, Property.TotalMonitorTime, monitorTime, FilterOperator.NotEquals); } @@ -1554,9 +1556,9 @@ public void Data_QueryFilter_SensorProperties_TotalMonitorTime_NotEquals() [IntegrationTest] public void Data_QueryFilter_SensorProperties_TotalMonitorTime_GreaterThan() { - var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime; + var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime.Subtract(TimeSpan.FromSeconds(10)); - Assert.IsNotNull(monitorTime); + Assert.IsTrue(monitorTime.TotalSeconds >= 0, "Cannot test TotalMonitorTime if TotalSeconds value is 0"); ExecuteSensor(s => s.TotalMonitorTime > monitorTime, Property.TotalMonitorTime, monitorTime, FilterOperator.GreaterThan); } @@ -1565,9 +1567,9 @@ public void Data_QueryFilter_SensorProperties_TotalMonitorTime_GreaterThan() [IntegrationTest] public void Data_QueryFilter_SensorProperties_TotalMonitorTime_LessThan() { - var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime; + var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime.Add(TimeSpan.FromSeconds(10)); - Assert.IsNotNull(monitorTime); + Assert.IsTrue(monitorTime.TotalSeconds >= 10, "Cannot test TotalMonitorTime if TotalSeconds value is 0"); ExecuteSensor(s => s.TotalMonitorTime < monitorTime, Property.TotalMonitorTime, monitorTime, FilterOperator.LessThan); } @@ -1578,7 +1580,7 @@ public void Data_QueryFilter_SensorProperties_TotalMonitorTime_Contains() { var monitorTime = client.GetSensor(Settings.UpSensor).TotalMonitorTime; - Assert.IsNotNull(monitorTime); + Assert.IsTrue(monitorTime.TotalSeconds >= 0, "Cannot test TotalMonitorTime if TotalSeconds value is 0"); ExecuteSensor(s => s.TotalMonitorTime.ToString().Contains(monitorTime.ToString()), Property.TotalMonitorTime, monitorTime); } @@ -1776,9 +1778,12 @@ public void Data_QueryFilter_SensorProperties_Uptime_Contains() [IntegrationTest] public void Data_QueryFilter_DeviceProperties_Condition_Equals() { - PrepareCondition(device => + Retry(retry => { - ExecuteDevice(d => d.Condition == device.Condition, Property.Condition, device.Condition); + PrepareCondition(device => + { + ExecuteDevice(d => d.Condition == device.Condition, Property.Condition, device.Condition); + }); }); } @@ -1816,9 +1821,12 @@ public void Data_QueryFilter_DeviceProperties_Condition_LessThan() [IntegrationTest] public void Data_QueryFilter_DeviceProperties_Condition_Contains() { - PrepareCondition(device => + Retry(retry => { - ExecuteDevice(d => d.Condition.Contains(device.Condition), Property.Condition, device.Condition, FilterOperator.Contains); + PrepareCondition(device => + { + ExecuteDevice(d => d.Condition.Contains(device.Condition), Property.Condition, device.Condition, FilterOperator.Contains); + }); }); } @@ -2536,13 +2544,13 @@ private void ExecuteObject( { if (retry) { - Assert.IsTrue(linqObjects.Count > 0); Assert.IsTrue(filterObjects.Count > 0); + Assert.IsTrue(linqObjects.Count > 0); Assert.IsTrue(queryObjects.Count > 0); } + AssertEx.IsTrue(filterObjects.Count > 0, "Filter objects did not return any results. Are there even any results that match the specified search criteria?"); AssertEx.IsTrue(linqObjects.Count > 0, "LINQ objects did not return any results"); - AssertEx.IsTrue(filterObjects.Count > 0, "Filter objects did not return any results"); AssertEx.IsTrue(queryObjects.Count > 0, "Query objects did not return any results"); } diff --git a/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/AddObjectTests.cs b/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/AddObjectTests.cs index 33660c26..3d508969 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/AddObjectTests.cs +++ b/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/AddObjectTests.cs @@ -167,7 +167,7 @@ private void AddToInvalidObject(int objectId) AssertEx.Throws( () => client.AddSensor(objectId, parameters), - "The desired object cannot be created here" + "object cannot be created here" ); } diff --git a/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/StateTests.cs b/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/StateTests.cs index c6d55eca..10f9e4ab 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/StateTests.cs +++ b/src/PrtgAPI.Tests.IntegrationTests/CSharp/ObjectManipulation/StateTests.cs @@ -11,7 +11,12 @@ public class PrtgClientStateTests : BasePrtgClientTest [IntegrationTest] public void Action_State_AcknowledgeAndResume() { - AssertEx.AreEqual(Status.Down, GetSensor(Settings.DownSensor).Status, $"Initial sensor status was not {Status.Down}"); + var initial = GetSensor(Settings.DownSensor); + + if (initial.Status != Status.Down) + ServerManager.RepairConfig(); + + AssertEx.AreEqual(Status.Down, initial.Status, "Initial status was not down"); var message = "Unit Testing FTW!"; @@ -34,6 +39,16 @@ public void Action_State_AcknowledgeAndResume() [IntegrationTest] public void Action_State_PauseAndResume() { + var initial = GetSensor(Settings.UpSensor); + + if (initial.Status != Status.Up) + { + client.ResumeObject(initial.Id); + ServerManager.RepairConfig(); + } + + AssertEx.AreEqual(Status.Up, initial.Status, "Initial status was not up"); + Logger.LogTestDetail("Pausing object"); client.PauseObject(Settings.UpSensor); CheckAndSleep(Settings.UpSensor); @@ -68,6 +83,12 @@ public void Action_State_PauseForDuration() { var initial = GetSensor(Settings.UpSensor); + if (initial.Status != Status.Up) + { + client.ResumeObject(initial.Id); + ServerManager.RepairConfig(); + } + AssertEx.AreEqual(Status.Up, initial.Status, "Initial status was not up"); Logger.LogTestDetail("Pausing for 1 minute"); @@ -111,7 +132,12 @@ public void Action_State_PauseForDuration() [IntegrationTest] public void Action_State_SimulateErrorAndResume() { - AssertEx.AreEqual(Status.Up, GetSensor(Settings.UpSensor).Status, $"Initial sensor state was not {Status.Up}"); + var initial = GetSensor(Settings.UpSensor); + + if (initial.Status != Status.Up) + ServerManager.RepairConfig(); + + AssertEx.AreEqual(Status.Up, initial.Status, "Initial status was not up"); Logger.LogTestDetail("Simulating error status"); client.SimulateError(Settings.UpSensor); diff --git a/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectData/Get-SensorTarget.Tests.ps1 b/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectData/Get-SensorTarget.Tests.ps1 index 2306806e..5880410f 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectData/Get-SensorTarget.Tests.ps1 +++ b/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectData/Get-SensorTarget.Tests.ps1 @@ -126,7 +126,7 @@ Describe "Get-SensorTarget_IT" -Tag @("PowerShell", "IntegrationTest") { It "throws retrieving targets for a sensor type unsupported by a device" { - { $device | Get-SensorTarget -RawType exchangepsbackup } | Should Throw "An unspecified error occurred while trying to resolve sensor targets. Specified sensor type may not be valid on this device" + { $device | Get-SensorTarget -RawType exchangepsbackup } | Should Throw "Specified sensor type may not be valid on this device" } It "throws attempting to resolve sensor targets as a read-only user" { diff --git a/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/ObjectProperty/Set-ObjectProperty.Container.Tests.ps1 b/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/ObjectProperty/Set-ObjectProperty.Container.Tests.ps1 index e8a4625b..276ea1c8 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/ObjectProperty/Set-ObjectProperty.Container.Tests.ps1 +++ b/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/ObjectProperty/Set-ObjectProperty.Container.Tests.ps1 @@ -27,8 +27,8 @@ Describe "Set-ObjectProperty_Containers_IT" -Tag @("PowerShell", "IntegrationTes { SetChild "Location" "410 Terry Ave. North Seattle" "InheritLocation" $false } | Should Throw "410 Terry Ave N, Seattle, WA 98109, United States" # Location: Coordinates - $lat = 51.4521018 - $lon = 13.0766654 + $lat = 51.4521 + $lon = 13.077 SetValue "Location" "$lat, $lon" $true $prop = $object | Get-ObjectProperty diff --git a/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/Pause-Object.Tests.ps1 b/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/Pause-Object.Tests.ps1 index e3f4abbb..614c9453 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/Pause-Object.Tests.ps1 +++ b/src/PrtgAPI.Tests.IntegrationTests/PowerShell/ObjectManipulation/Pause-Object.Tests.ps1 @@ -53,7 +53,7 @@ Describe "Pause-Object_IT" -Tag @("PowerShell", "IntegrationTest") { $pausedSensor = WaitForStatus $pausedSensor Up 90 LogTestDetail "Object should be unpaused. Refreshing object." - $finalSensor = WaitForStatus $pausedSensor Up 30 10 + $finalSensor = WaitForStatus $pausedSensor Up 60 5 $finalSensor.Status | Should Be Up } @@ -76,7 +76,7 @@ Describe "Pause-Object_IT" -Tag @("PowerShell", "IntegrationTest") { $pausedSensor = WaitForStatus $pausedSensor Up 90 LogTestDetail "Object should be unpaused. Refreshing object." - $finalSensor = WaitForStatus $pausedSensor Up 30 10 + $finalSensor = WaitForStatus $pausedSensor Up 60 5 $finalSensor.Status | Should Be Up } diff --git a/src/PrtgAPI.Tests.IntegrationTests/PrtgAPI.Tests.IntegrationTests.csproj b/src/PrtgAPI.Tests.IntegrationTests/PrtgAPI.Tests.IntegrationTests.csproj index 7a3cdf3e..75d3990c 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/PrtgAPI.Tests.IntegrationTests.csproj +++ b/src/PrtgAPI.Tests.IntegrationTests/PrtgAPI.Tests.IntegrationTests.csproj @@ -107,6 +107,7 @@ + diff --git a/src/PrtgAPI.Tests.IntegrationTests/Support/ServerManager.cs b/src/PrtgAPI.Tests.IntegrationTests/Support/ServerManager.cs index 4fbab2e3..9b2eb760 100644 --- a/src/PrtgAPI.Tests.IntegrationTests/Support/ServerManager.cs +++ b/src/PrtgAPI.Tests.IntegrationTests/Support/ServerManager.cs @@ -6,6 +6,7 @@ using System.Net.NetworkInformation; using System.ServiceProcess; using System.Threading; +using PrtgAPI.Tests.IntegrationTests.Support; namespace PrtgAPI.Tests.IntegrationTests { @@ -253,16 +254,14 @@ private void RemoteInit() { Logger.Log("Restoring PRTG Config leftover from previous aborted test"); Logger.LogTest("Stopping PRTGCoreService"); - coreService.Stop(); - coreService.WaitForStatus(ServiceControllerStatus.Stopped); + coreService.StopAndWaitForStatus(ServiceControllerStatus.Stopped); Logger.LogTest("Copying PRTG Config"); File.Copy(PrtgConfigBackup, PrtgConfig, true); File.Delete(PrtgConfigBackup); Logger.LogTest("Starting PRTGCoreService"); - coreService.Start(); - coreService.WaitForStatus(ServiceControllerStatus.Running); + coreService.StartAndWaitForStatus(ServiceControllerStatus.Running); Logger.LogTest("Sleeping for 30 seconds while PRTG starts up"); Thread.Sleep(30 * 1000); @@ -330,8 +329,7 @@ private void RemoteCleanup(bool deleteConfig, bool restoreConfig = true) Logger.Log("Starting service"); - coreService.Start(); - coreService.WaitForStatus(ServiceControllerStatus.Running); + coreService.StartAndWaitForStatus(ServiceControllerStatus.Running); if (probeNameNeedsRepairing) { @@ -351,8 +349,7 @@ private void RemoteCleanup(bool deleteConfig, bool restoreConfig = true) if (probeService.Status != ServiceControllerStatus.Stopped) Thread.Sleep(5000); - probeService.Start(); - probeService.WaitForStatus(ServiceControllerStatus.Running); + probeService.StartAndWaitForStatus(ServiceControllerStatus.Running); } Logger.Log("Finished"); @@ -471,8 +468,7 @@ private void StartService(ServiceController service, string friendlyName, bool r if (service.Status == ServiceControllerStatus.Stopped) { Logger.LogTest($"{service.ServiceName} is not running. Starting service"); - service.Start(); - service.WaitForStatus(ServiceControllerStatus.Running); + service.StartAndWaitForStatus(ServiceControllerStatus.Running); Logger.LogTest("Sleeping for 30 seconds while PRTG service starts"); Thread.Sleep(30 * 1000); diff --git a/src/PrtgAPI.Tests.IntegrationTests/Support/ServiceControllerExtensions.cs b/src/PrtgAPI.Tests.IntegrationTests/Support/ServiceControllerExtensions.cs new file mode 100644 index 00000000..55dffcc7 --- /dev/null +++ b/src/PrtgAPI.Tests.IntegrationTests/Support/ServiceControllerExtensions.cs @@ -0,0 +1,62 @@ +using System; +using System.ServiceProcess; + +namespace PrtgAPI.Tests.IntegrationTests.Support +{ + internal static class ServiceControllerExtensions + { + internal static void StartAndWaitForStatus(this ServiceController service, ServiceControllerStatus status = ServiceControllerStatus.Running) + { + var timeout = TimeSpan.FromSeconds(10); + + service.Start(); + + for (var i = 0; i < 10; i++) + { + try + { + service.WaitForStatus(status, timeout); + + return; + } + catch + { + if (service.Status == ServiceControllerStatus.Stopped) + { + service = new ServiceController(service.ServiceName, service.MachineName); + service.Start(); + } + } + } + + throw new InvalidOperationException($"Failed to start service '{service.ServiceName}': service doesn't want to start"); + } + + internal static void StopAndWaitForStatus(this ServiceController service, ServiceControllerStatus status = ServiceControllerStatus.Stopped) + { + var timeout = TimeSpan.FromSeconds(10); + + service.Stop(); + + for (var i = 0; i < 10; i++) + { + try + { + service.WaitForStatus(status, timeout); + + return; + } + catch + { + if (service.Status == ServiceControllerStatus.Running) + { + service = new ServiceController(service.ServiceName, service.MachineName); + service.Stop(); + } + } + } + + throw new InvalidOperationException($"Failed to start service '{service.ServiceName}': service doesn't want to start"); + } + } +} diff --git a/src/PrtgAPI.Tests.UnitTests/PowerShell/Infrastructure/GoPrtg/Uninstall-GoPrtgServer.Tests.ps1 b/src/PrtgAPI.Tests.UnitTests/PowerShell/Infrastructure/GoPrtg/Uninstall-GoPrtgServer.Tests.ps1 index f8c8b733..a39d5985 100644 --- a/src/PrtgAPI.Tests.UnitTests/PowerShell/Infrastructure/GoPrtg/Uninstall-GoPrtgServer.Tests.ps1 +++ b/src/PrtgAPI.Tests.UnitTests/PowerShell/Infrastructure/GoPrtg/Uninstall-GoPrtgServer.Tests.ps1 @@ -170,7 +170,7 @@ Describe "Uninstall-GoPrtgServer" -Tag @("PowerShell", "UnitTest") { Uninstall-GoPrtgServer - { __goPrtgGetServers } | Should Throw "The term '__goPrtgGetServers' is not recognized as the name of a cmdlet" + { __goPrtgGetServers } | Should Throw "The term '__goPrtgGetServers' is not recognized" } It "removes the global function" { @@ -178,7 +178,7 @@ Describe "Uninstall-GoPrtgServer" -Tag @("PowerShell", "UnitTest") { Uninstall-GoPrtgServer - { __goPrtgGetServers } | Should Throw "The term '__goPrtgGetServers' is not recognized as the name of a cmdlet" + { __goPrtgGetServers } | Should Throw "The term '__goPrtgGetServers' is not recognized" } It "updates the global function" { diff --git a/src/PrtgAPI.Tests.UnitTests/PowerShell/ObjectData/Get-SensorHistory.Tests.ps1 b/src/PrtgAPI.Tests.UnitTests/PowerShell/ObjectData/Get-SensorHistory.Tests.ps1 index 25f0263e..e436fc44 100644 --- a/src/PrtgAPI.Tests.UnitTests/PowerShell/ObjectData/Get-SensorHistory.Tests.ps1 +++ b/src/PrtgAPI.Tests.UnitTests/PowerShell/ObjectData/Get-SensorHistory.Tests.ps1 @@ -154,11 +154,13 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = Get-Date $end = $start.AddDays(-1) - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&sortby=-datetime&count=0") [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&sortby=-datetime&count=500") ) + $response.AllowSecondDifference = $true + $items = $sensor | Get-SensorHistory -StartDate $start -EndDate $end $items.Count | Should Be 2 @@ -254,7 +256,8 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = Get-Date $end = $start.AddHours(-1).AddMinutes(-4) - SetAddressValidatorResponse "historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=4&sortby=-datetime" + $response = SetAddressValidatorResponse "historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=4&sortby=-datetime" + $response.AllowSecondDifference = $true $items = $sensor | Get-SensorHistory -Count 4 -StartDate $start @@ -266,11 +269,13 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = Get-Date $end = $start.AddDays(-1) - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=0&sortby=-datetime") [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&sortby=-datetime&count=500") ) + $response.AllowSecondDifference = $true + $items = @($sensor | Get-SensorHistory -StartDate $start -EndDate $end -Count 1) $items.Count | Should Be 1 @@ -284,10 +289,12 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $s = Run Sensor { Get-Sensor } $s.Interval | Should Be "00:01:00" - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=120&sortby=-datetime") ) + $response.AllowSecondDifference = $true + $s | Get-SensorHistory -Count 120 } @@ -299,11 +306,13 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $s = Run Sensor { Get-Sensor } $s.Interval | Should Be "00:01:00" - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=0&sortby=-datetime") [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&sortby=-datetime&count=500") ) + $response.AllowSecondDifference = $true + $s | Get-SensorHistory -Count 120 -StartDate $start -EndDate $end } @@ -311,10 +320,12 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = (Get-Date) $end = $start.AddDays(-20).AddHours(-1) - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=20&sortby=-datetime") ) + $response.AllowSecondDifference = $true + $s = Run Sensor { Get-Sensor } $s.Interval = "01:00:00:00" $s.Interval | Should Be "1.00:00:00" @@ -327,11 +338,13 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = (Get-Date) $end = $start.AddHours(-2).AddMinutes(-10) - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Sensors("filter_objid=4000", [Request]::DefaultObjectFlags) [Request]::Get("api/historicdata.xml?id=4000&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&count=70&sortby=-datetime") ) + $response.AllowSecondDifference = $true + Get-SensorHistory -Id 4000 -Count 70 -StartDate $start } @@ -340,10 +353,12 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = (Get-Date) $end = $start.AddHours(-7).AddMinutes(-40) - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=300&count=80&sortby=-datetime") ) + $response.AllowSecondDifference = $true + $s = Run Sensor { Get-Sensor } $s.Interval | Should Be "00:01:00" @@ -355,9 +370,10 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { $start = (Get-Date) $end = $start.AddHours(-6).AddMinutes(-50) - SetAddressValidatorResponse @( + $response = SetAddressValidatorResponse @( [Request]::Get("api/historicdata.xml?id=4000&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=300&count=70&sortby=-datetime") ) + $response.AllowSecondDifference = $true Get-SensorHistory -Id 4000 -Count 70 -Average 300 } @@ -373,6 +389,7 @@ Describe "Get-SensorHistory" -Tag @("PowerShell", "UnitTest") { [Request]::Get("api/historicdata.xml?id=2203&edate=$($start.ToString($format))&sdate=$($end.ToString($format))&avg=0&sortby=-datetime&count=500&start=500") ) + $response.AllowSecondDifference = $true $response.FixedCountOverride = 1000 $items = @($sensor | Get-SensorHistory -StartDate $start -EndDate $end -Count 1000) diff --git a/src/PrtgAPI.Tests.UnitTests/Support/TestResponses/AddressValidatorResponse.cs b/src/PrtgAPI.Tests.UnitTests/Support/TestResponses/AddressValidatorResponse.cs index e7749548..843b749c 100644 --- a/src/PrtgAPI.Tests.UnitTests/Support/TestResponses/AddressValidatorResponse.cs +++ b/src/PrtgAPI.Tests.UnitTests/Support/TestResponses/AddressValidatorResponse.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; +using PrtgAPI.Request.Serialization; using PrtgAPI.Utilities; namespace PrtgAPI.Tests.UnitTests.Support.TestResponses @@ -19,6 +20,8 @@ public class AddressValidatorResponse : MultiTypeResponse public bool AllowReorder { get; set; } + public bool AllowSecondDifference { get; set; } + [Obsolete("Do not create AddressValidatorResponse objects directly; use BaseTest.Execute instead")] public AddressValidatorResponse(string str) { @@ -101,7 +104,10 @@ internal void ValidateAddress(string address) if (AllowReorder) AssertEx.UrlsEquivalent(strArray[arrayPos], address); else - throw GetDifference(strArray[arrayPos], address, ex); + { + if (!(AllowSecondDifference && AssertSecondDifferenceEqual(strArray[arrayPos], address))) + throw GetDifference(strArray[arrayPos], address, ex); + } } } @@ -122,6 +128,38 @@ internal void ValidateAddress(string address) } } + private bool AssertSecondDifferenceEqual(string expected, string actual) + { + var expectedParts = UrlUtilities.CrackUrl(expected); + var actualParts = UrlUtilities.CrackUrl(actual); + + var differingParts = actualParts.AllKeys.Select(k => new + { + Expected = expectedParts[k], + Actual = actualParts[k], + Key = k + }).Where(a => a.Expected != a.Actual).ToArray(); + + if (differingParts.Length == 1) + { + var part = differingParts[0]; + + switch (part.Key) + { + case "sdate": + var expectedDate = TypeHelpers.StringToDate(part.Expected); + var actualDate = TypeHelpers.StringToDate(part.Actual); + + if (expectedDate.AddSeconds(1) == actualDate) + return true; + + break; + } + } + + return false; + } + private AssertFailedException GetDifference(string expected, string actual, AssertFailedException originalException) { var expectedParts = UrlUtilities.CrackUrl(expected); diff --git a/src/PrtgAPI/Enums/Serialization/SensorTypeInternal.cs b/src/PrtgAPI/Enums/Serialization/SensorTypeInternal.cs index 145f8d3ac12fa036837e35cd8cd4e13025e1182b..01ed00cabb74a6b031de2f94ed027b579f43b5a5 100644 GIT binary patch delta 4053 zcmbVPdu*H46~8A=^J;?YIBs4v`Rt@h6R1-sO*`))H7YHPL7LDoXeyfd5rS!A$FUP= zk-ApOs*#0}^n~91!6-vjmzIVRKER?XQi>|JQo)*`v96mc((Mn1Hc|G+q)qH`&h^_4 zA)PFLy5Bwbp7;5k^L@0KKmA6*t0yaPO@2YXM+8JjgwdLBHa{eG3r)C$hkgMuBK)); zEWNv2ogm5%@uV0M14J7ZePS3F3tg>4biR)`glM1kgk9WE^g;T!3+87h`V&Nr$)Wc) zbmTfqqO!KrIhKCG(vZ(P^p3q_{rbs@=|b$(eh4mfbeH1|ZJ<3{P;|$m6dDm;V*Qv1 z({D)hic!%*&k(8Przb0HN5?BpJZ>#pr7@L6uE&ekQfaFMzrM|O9iS82Z6miRaY*<` zLjN)n!*!_=U#g2qtf|)w^2K-HHmtZZ|46oRUQ&HP`E-zcXJ;=dGh8IBkHkGng4yFC zaX``f$mdI%EgZ`5$D4}qi;oHlA0%~s#OnZld!gD8cf^&Zg1Q|Px$PoB7dvATb|)oB zYbAv6Cnt)H9ttZf?TIlv(pZk$K6qizts9cTX(dKDl1gfnG^vi!$b>Y_C~Z@W+?Z)( z`t6LnY;HfLVJ@!y&ADB-ZrXsVp%p}>VL5~DqnLE0n~@c(bTibAr1H}z*2wuqD8PSx z_HI{L*HGj1&qf`}7P(mQ70(V{hL2%#9`0v zx_h5y#KS?G{>oraj$S|fUBC^YDm?5ez*C{`;V1i#>k~sq0XNmG)o%|!Zz1or;hbR) zzVM?WtQqf6?~dGR93L-I>kFrj;Mu2(VHAHobAV1gOsmtUo0$%yx?|!J7#Z%uWMUN5 zywcPIl?K8;x$8ct#hNF}N?OGh(MGC=sHoi7m1~wK$Km1q*tCbjb9XsV*Ien zXU2Cd^{7pi)<(~#pXQ2ch+dqeF|z!?cyN$o9i(%l)Wnnr7LmWt^zr%!pA=ArBdO3^caQL zPwX?gzi5qzZ5|eTTz(M3Kwd>&vOyh^i;@63l!*8KOQrz=Dc7ur+$l{ z|9723%7WxUJL&3C(}_o2Z6WX8%k}6>ui9Y|O*_5fk zR^_Oi>9aBYH13%2-6P4^Nw?o!RxtBTV_u(tO*U+O**ovBPODaLTJ zbZnJttCI?58N)HIjMKBJ*4bxJo6Oa3Ob?YNPd=P5Uv_$?ucRTl)~HJ zE3Ew%JslH4d~wE3RHs7g_`REFy49X(rjbqsUq&RM~qP@I|}YCt1YMBKik4ttbVu`Wluj8{xy#Ntyt4O7YCf^F{-(9Yul-(b#R zTC?Y}_c#Yrxn>r)1B0J9o4GY|MQ{OYl=YdMd6G`yf)_q*yCd~Z_Kmdja`8L_@cxpp3Uisj!g5NY2f`1m$?_%e(c9KtDob_RNne+U)el#bs)0G#}l zCtv+7Y{KD}ACQyJK(0LZ6oeyhUWI###t%(|VQfZZ;&X)rNqqaP~4z=o=-H8@-EWb4)a0-&cx%O1FgK(L;gc>x4_ zsMaB&KG(>a>M|ubZ*s8OpuGSGCLF9g(jwuP8-2_ZjRITjZ3nfFfvZ~d_wsd1ix+Ns z&}}bgQh(H>X(R`6MsphdV=}Ie9vAigtU~lYlm))~D}v$Cd}zeT#x<@wCD;>x_NoeK zWDt7=G+qfZt9U%3LH&{9>=0=uZMYoYckh5?Y3n3@Vk04Po^+5lQqHlDGiL?Ib^HvH zPI6_73vy-PKZlKX&+$6IeXZmocZ5h6so;!mnrL;;-}2B+fILA+4?G#aymOwGk$R*FmEX$Su_BOO`;1DgFhx>yNWwCN1gDXSxJ z$wYt5fI$f-AP9779Cj&&S-8GOT$6YXIwkcETJl8c{th|H;m>e1TYb+#MIHMF-u&&h Xbq!W@Nxd{DZ*%Libbkj8TP4e1pQ!}+ diff --git a/src/PrtgAPI/Request/ResponseParser.cs b/src/PrtgAPI/Request/ResponseParser.cs index bfa06933..787b51a5 100644 --- a/src/PrtgAPI/Request/ResponseParser.cs +++ b/src/PrtgAPI/Request/ResponseParser.cs @@ -569,19 +569,19 @@ internal static void ProcessAddSensorProgressFailed(NameValueCollection parts, s { message = message.Trim('\r', '\n'); - //todo: does this work in other languages? Not sure how to replicate it + //todo: does this work in other languages? Not sure how to replicate it. when we test with every single sensor type we get this in an _enhanced_ exception message below if (message.StartsWith("Incomplete connection settings")) throw new PrtgRequestException("Failed to retrieve data from device; required credentials for sensor type may be missing. See PRTG UI for further details."); throw new PrtgRequestException($"An exception occurred while trying to {action}: {message.EnsurePeriod()}"); } + var invalidStr = "Specified sensor type may not be valid on this device, or sensor query target parameters may be incorrect. Check the Device 'Host' is still valid or try adding sensor with the PRTG UI."; + if (enhancedErrorMessage != null) - throw new PrtgRequestException($"An exception occurred while trying to {action}: {enhancedErrorMessage.EnsurePeriod()}"); + throw new PrtgRequestException($"An exception occurred while trying to {action}: {enhancedErrorMessage.EnsurePeriod()} {invalidStr.EnsurePeriod()}"); else - { - throw new PrtgRequestException($"An unspecified error occurred while trying to {action}. Specified sensor type may not be valid on this device, or sensor query target parameters may be incorrect. Check the Device 'Host' is still valid or try adding sensor with the PRTG UI."); - } + throw new PrtgRequestException($"An unspecified error occurred while trying to {action}. {invalidStr.EnsurePeriod()}"); } #endregion diff --git a/src/PrtgAPI/Utilities/StringExtensions.cs b/src/PrtgAPI/Utilities/StringExtensions.cs index 25d9c417..a84cb80c 100644 --- a/src/PrtgAPI/Utilities/StringExtensions.cs +++ b/src/PrtgAPI/Utilities/StringExtensions.cs @@ -53,7 +53,7 @@ public static string EnsurePeriod(this string str) if (str == null) return "."; - if (str.EndsWith(".")) + if (str.EndsWith(".") || str.EndsWith("?") || str.EndsWith("!")) return str; return $"{str}.";