Skip to content

Commit

Permalink
Fix ServerStatus.DateTime crashing when the server DateTime format di…
Browse files Browse the repository at this point in the history
…ffers from the client format (e.g. US vs UK time format)
  • Loading branch information
lordmilko committed Jul 25, 2020
1 parent 9a9ae28 commit 3524403
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 20 deletions.
18 changes: 18 additions & 0 deletions src/PrtgAPI.Tests.UnitTests/CSharp/BaseTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using PrtgAPI.Reflection;
using PrtgAPI.Tests.UnitTests.Support.TestItems;
Expand Down Expand Up @@ -109,6 +111,22 @@ protected T Execute<T>(Func<PrtgClient, T> action)
return action(client);
}

protected void TestCustomCulture(Action action, CultureInfo newCulture)
{
var originalCulture = Thread.CurrentThread.CurrentCulture;

try
{
Thread.CurrentThread.CurrentCulture = newCulture;

action();
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}

private AddressValidatorResponse GetValidator(object urls, Dictionary<Content, int> countOverride, Dictionary<Content, BaseItem[]> itemOverride)
{
#pragma warning disable 618
Expand Down
119 changes: 118 additions & 1 deletion src/PrtgAPI.Tests.UnitTests/CSharp/ObjectData/ServerStatusTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Threading.Tasks;
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PrtgAPI.Tests.UnitTests.Support.TestItems;
using PrtgAPI.Tests.UnitTests.Support.TestResponses;
Expand Down Expand Up @@ -123,6 +125,121 @@ public async Task ServerStatus_ReadOnlyAsync()
AssertEx.AllPropertiesRetrieveValues(result);
}

[UnitTest]
[TestMethod]
public void ServerStatus_DateTime_ServerUS_ClientUK()
{
//There's a legal mismatch, so we get the dates backwards
TestClockSmallDate(
"MM/d/yyyy",
"en-GB",
expectedClientMonth: 12,
expectedClientDay: 1
);

//There's an illegal mismatch, so we reparse the DateTime using US heuristics
TestClockLargeDate(
"MM/d/yyyy",
"en-GB",
expectedClientMonth: 1,
expectedClientDay: 13
);
}

[UnitTest]
[TestMethod]
public void ServerStatus_DateTime_ServerUS_ClientUS()
{
TestClockSmallDate(
"MM/d/yyyy",
"en-US",
expectedClientMonth: 1,
expectedClientDay: 12
);

TestClockLargeDate(
"MM/d/yyyy",
"en-US",
expectedClientMonth: 1,
expectedClientDay: 13
);
}

[UnitTest]
[TestMethod]
public void ServerStatus_DateTime_ServerUK_ClientUS()
{
//There's a legal mismatch, so we get the dates backwards
TestClockSmallDate(
"dd/MM/yyyy",
"en-US",
expectedClientMonth: 12,
expectedClientDay: 1
);

//There's an illegal mismatch, so we reparse the DateTime using US heuristics
TestClockLargeDate(
"dd/MM/yyyy",
"en-US",
expectedClientMonth: 1,
expectedClientDay: 13
);
}

[UnitTest]
[TestMethod]
public void ServerStatus_DateTime_ServerUK_ClientUK()
{
TestClockSmallDate(
"dd/MM/yyyy",
"en-GB",
expectedClientMonth: 1,
expectedClientDay: 12
);

TestClockLargeDate(
"dd/MM/yyyy",
"en-GB",
expectedClientMonth: 1,
expectedClientDay: 13
);
}

private void TestClockSmallDate(
string serverDateFormat,
string clientCulture,
int expectedClientMonth,
int expectedClientDay)
{
var serverTime = new DateTime(2020, 1, 12, 4, 10, 20, DateTimeKind.Utc).ToLocalTime().ToString($"{serverDateFormat} h:mm:ss tt");

TestClock(serverTime, clientCulture, new DateTime(2020, expectedClientMonth, expectedClientDay, 4, 10, 20, DateTimeKind.Utc));
}

private void TestClockLargeDate(
string serverDateFormat,
string clientCulture,
int expectedClientMonth,
int expectedClientDay)
{
var serverTime = new DateTime(2020, 1, 13, 4, 10, 20, DateTimeKind.Utc).ToLocalTime().ToString($"{serverDateFormat} h:mm:ss tt");

TestClock(serverTime, clientCulture, new DateTime(2020, expectedClientMonth, expectedClientDay, 4, 10, 20, DateTimeKind.Utc));
}

private void TestClock(string serverTime, string clientCulture, DateTime expectedInvariantUtc)
{
var client = Initialize_Client(new ServerStatusResponse(new ServerStatusItem(clock: serverTime)));

TestCustomCulture(() =>
{
var now = DateTime.Now.ToString();

var status = client.GetStatus();
Assert.AreEqual(expectedInvariantUtc, status.DateTime.ToUniversalTime());
}, CultureInfo.GetCultureInfo(clientCulture));
}

public ServerStatusItem GetItem() => new ServerStatusItem();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -872,22 +872,6 @@ public void SetObjectProperty_DecimalPoint_EuropeanCulture()
}, new CultureInfo("de-DE"));
}

private void TestCustomCulture(Action action, CultureInfo newCulture)
{
var originalCulture = Thread.CurrentThread.CurrentCulture;

try
{
Thread.CurrentThread.CurrentCulture = newCulture;

action();
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture;
}
}

#endregion
#region Multiple

Expand Down
25 changes: 22 additions & 3 deletions src/PrtgAPI/Objects/Models/ServerStatus.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.Runtime.Serialization;
using PrtgAPI.Request.Serialization;
using PrtgAPI.Utilities;
Expand All @@ -18,14 +19,32 @@ public class ServerStatus
private DateTime? clock;

/// <summary>
/// Current system time on the PRTG Core Server.
/// Current system time on the PRTG Core Server.<para/>
/// Note that if the DateTime format of the PRTG Server's language region does not match the DateTime format of the
/// system running PrtgAPI,<para/>
/// the DateTime format of the value parsed by this property may have months and dates back to front.
/// </summary>
public DateTime DateTime
{
get
{
if (clock == null)
clock = DateTime.Parse(clockStr);
{
//Try and parse the remote DateTime based on the DateTime of the local system. If that fails, we have no idea whether the remote
//system was dd/MM/yyyy or MM/dd/yyyy so just try both. We might not be right if we're on the 1st-12th of the month,
//but it's the best we can do with an ambiguous date format.
DateTime temp;

var ukCulture = CultureInfo.GetCultureInfo("en-GB").DateTimeFormat;
var usCulture = CultureInfo.GetCultureInfo("en-US").DateTimeFormat;

if (DateTime.TryParse(clockStr, out temp))
clock = temp;
else if (DateTime.TryParse(clockStr, ukCulture, DateTimeStyles.None, out temp))
clock = temp;
else
clock = DateTime.Parse(clockStr, usCulture);
}

return clock.Value;
}
Expand Down Expand Up @@ -154,7 +173,7 @@ public string UserId
private string userTimeZone;

/// <summary>
/// UTC offset of your PRTG Server's timezone.
/// UTC offset or name of your PRTG Server's timezone.
/// </summary>
[DataMember(Name = "UserTimeZone")]
public string UserTimeZone
Expand Down

0 comments on commit 3524403

Please sign in to comment.