diff --git a/src/QueryMaster.UnitTests/Properties/AssemblyInfo.cs b/src/QueryMaster.UnitTests/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..545d9f23
--- /dev/null
+++ b/src/QueryMaster.UnitTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("QueryMaster.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Bletch1971")]
+[assembly: AssemblyProduct("QueryMaster.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2015-2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("812FAA07-FFE2-4F09-A93E-5704E544E61C")]
+
+// exclude from semantic versioning
+[assembly: AssemblyVersion("1.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/QueryMaster.UnitTests/QueryMaster.UnitTests.csproj b/src/QueryMaster.UnitTests/QueryMaster.UnitTests.csproj
new file mode 100644
index 00000000..7a3e0cbc
--- /dev/null
+++ b/src/QueryMaster.UnitTests/QueryMaster.UnitTests.csproj
@@ -0,0 +1,23 @@
+
+
+ net462
+ false
+ QueryMaster.UnitTests
+ QueryMaster.UnitTests
+
+
+ none
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/QueryMaster.UnitTests/ServerQueryTests.cs b/src/QueryMaster.UnitTests/ServerQueryTests.cs
new file mode 100644
index 00000000..2d1c48c5
--- /dev/null
+++ b/src/QueryMaster.UnitTests/ServerQueryTests.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Linq;
+using System.Net;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace QueryMaster.UnitTests
+{
+ [TestClass]
+ public class ServerQueryTests
+ {
+ private static readonly char[] rconLineSplitChars = new char[] { '\n' };
+
+ [DataTestMethod]
+ [DataRow("127.0.0.1", 27015)]
+ [DataRow("192.168.0.1", 27015)]
+ [DataRow("101.188.183.193", 27015)]
+ public void ServerQuery_PlayerCount(string ipAddressString, int queryPort)
+ {
+ var ipAddress = IPAddress.Parse(ipAddressString);
+ var endPoint = new IPEndPoint(ipAddress, queryPort);
+
+ using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, endPoint))
+ {
+ Assert.IsNotNull(gameServer);
+
+ var serverInfo = gameServer.GetInfo();
+ Assert.IsNotNull(serverInfo);
+
+ var playerCount1 = serverInfo.Players;
+
+ var players = gameServer.GetPlayers();
+ Assert.IsNotNull(players);
+
+ var validPlayers = players.Where(p => !string.IsNullOrWhiteSpace(p.Name?.Trim()));
+ var playerCount2 = validPlayers.Count();
+
+ Assert.AreEqual(playerCount1, playerCount2);
+ }
+ }
+
+ [DataTestMethod]
+ [DataRow("127.0.0.1", 32330, "p@ssword")]
+ [DataRow("192.168.0.1", 32330, "p@ssword")]
+ [DataRow("101.188.183.193", 32330, "p@ssword")]
+ public void ServerQuery_RconListPlayers(string ipAddressString, int queryPort, string rconPassword)
+ {
+ var ipAddress = IPAddress.Parse(ipAddressString);
+ var endPoint = new IPEndPoint(ipAddress, queryPort);
+
+ using (var gameServer = ServerQuery.GetServerInstance(EngineType.Source, endPoint))
+ {
+ Assert.IsNotNull(gameServer);
+
+ using (var rconConsole = gameServer.GetControl(rconPassword))
+ {
+ Assert.IsNotNull(rconConsole);
+
+ var result = rconConsole.SendCommand("listplayers");
+ Assert.IsNotNull(result);
+
+ var lines = result.Split(rconLineSplitChars, StringSplitOptions.RemoveEmptyEntries).Select(l => l.Trim()).ToArray();
+ Assert.IsNotNull(lines);
+ }
+ }
+ }
+ }
+}
diff --git a/src/QueryMaster.UnitTests/packages.config b/src/QueryMaster.UnitTests/packages.config
new file mode 100644
index 00000000..d13923d1
--- /dev/null
+++ b/src/QueryMaster.UnitTests/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Server-Managers.sln b/src/Server-Managers.sln
index 27809f16..cee803cb 100644
--- a/src/Server-Managers.sln
+++ b/src/Server-Managers.sln
@@ -50,6 +50,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerManager.Common.UnitTests", "ServerManager.Common.UnitTests\ServerManager.Common.UnitTests.csproj", "{18271A4E-6135-466A-BCF8-80E25446F454}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QueryMaster.UnitTests", "QueryMaster.UnitTests\QueryMaster.UnitTests.csproj", "{A2EEBC18-DAD8-415D-98E4-258EB12369C7}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - AutoBackup|Any CPU = Debug - AutoBackup|Any CPU
@@ -239,7 +241,6 @@ Global
{A8BFC452-5BE8-41E7-BD1D-C29B944185CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8BFC452-5BE8-41E7-BD1D-C29B944185CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8BFC452-5BE8-41E7-BD1D-C29B944185CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A8BFC452-5BE8-41E7-BD1D-C29B944185CE}.Release|Any CPU.Build.0 = Release|Any CPU
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Debug - AutoBackup|Any CPU.ActiveCfg = Debug|Any CPU
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Debug - AutoBackup|Any CPU.Build.0 = Debug|Any CPU
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Debug - AutoShutdown|Any CPU.ActiveCfg = Debug|Any CPU
@@ -251,7 +252,6 @@ Global
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E}.Release|Any CPU.Build.0 = Release|Any CPU
{C4C8000D-5E45-497C-A218-B95A1567010E}.Debug - AutoBackup|Any CPU.ActiveCfg = Debug|Any CPU
{C4C8000D-5E45-497C-A218-B95A1567010E}.Debug - AutoBackup|Any CPU.Build.0 = Debug|Any CPU
{C4C8000D-5E45-497C-A218-B95A1567010E}.Debug - AutoShutdown|Any CPU.ActiveCfg = Debug|Any CPU
@@ -275,7 +275,17 @@ Global
{18271A4E-6135-466A-BCF8-80E25446F454}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18271A4E-6135-466A-BCF8-80E25446F454}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18271A4E-6135-466A-BCF8-80E25446F454}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {18271A4E-6135-466A-BCF8-80E25446F454}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - AutoBackup|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - AutoBackup|Any CPU.Build.0 = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - AutoShutdown|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - AutoShutdown|Any CPU.Build.0 = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - AutoUpdate|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - AutoUpdate|Any CPU.Build.0 = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - Beta|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug - Beta|Any CPU.Build.0 = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -291,6 +301,7 @@ Global
{A8BFC452-5BE8-41E7-BD1D-C29B944185CE} = {F8DBCE70-4658-47CB-A508-B3951125F0ED}
{1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E} = {F8DBCE70-4658-47CB-A508-B3951125F0ED}
{18271A4E-6135-466A-BCF8-80E25446F454} = {A7B846EF-9884-44DB-AF8F-3173DF1B3B66}
+ {A2EEBC18-DAD8-415D-98E4-258EB12369C7} = {A7B846EF-9884-44DB-AF8F-3173DF1B3B66}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4201246C-6E53-4209-883D-A4F084C19187}