aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Utilities
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2025-08-02 21:38:19 +0300
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2025-08-02 21:38:19 +0300
commit0df9f37075dd697ac34f4ed2a2749f62aa27a654 (patch)
tree5d95103b41d4954eff9f266317c5a525e9a0e3e9 /Software/Visual_Studio/Utilities
parent4222eddece906d6f0877022c06b853deb5068472 (diff)
downloadTango-0df9f37075dd697ac34f4ed2a2749f62aa27a654.tar.gz
Tango-0df9f37075dd697ac34f4ed2a2749f62aa27a654.zip
Telemetry Testing.
Diffstat (limited to 'Software/Visual_Studio/Utilities')
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/App.config34
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Program.cs107
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Tango.Telemetry.Tester.IOT.CLI.csproj202
-rw-r--r--Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/packages.config77
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/App.config62
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/DatabaseHelper.cs33
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Logger.cs49
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockCheckpointsRecoveryClient.cs13
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockDestinationWithFailure.cs46
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockHistorySource.cs35
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockStreamingSource.cs45
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockTelemetry.cs21
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Program.cs120
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Properties/AssemblyInfo.cs36
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Tango.TelemetryTester.CLI.csproj83
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Verifications List.md90
-rw-r--r--Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/packages.config4
18 files changed, 1093 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/App.config b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/App.config
new file mode 100644
index 000000000..959eb4686
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/App.config
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+ </startup>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Program.cs b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Program.cs
new file mode 100644
index 000000000..cb8a79288
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Program.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.BL.Enumerations;
+using Tango.Telemetry.Destinations;
+using Tango.Telemetry.Sources;
+
+namespace Tango.Telemetry.Tester.IOT.CLI
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ TelemetryPublisher publisher = new TelemetryPublisher(new TelemetryPublisherConfiguration()
+ {
+ Environment = "DEV",
+ SerialNumber = "dev-machine",
+ MachineType = MachineTypes.TS1800,
+ HistorySourcesRequestInterval = TimeSpan.FromSeconds(1),
+ EnableBackoff = false,
+
+ }, null);
+
+ (publisher.StorageManager as TelemetryLiteDBStorageManager).EnableCheckPointsRecovery = false;
+
+ publisher.RegisterSource(new JobRunsTestSource());
+ publisher.RegisterDestination(new TelemetryAzureHubDestination("HostName=iot-twine-dev-weu.azure-devices.net;DeviceId=telemetry-dev-01;SharedAccessKey=cZhCMhiVL+TF7p13fpX+lFmyxoy8ZqCkbxUwumWw18Q="));
+
+ publisher.PublishResultAvailable += Publisher_PublishResultAvailable;
+
+ publisher.Start().GetAwaiter().GetResult();
+
+ Console.Clear();
+ Console.WriteLine("=== Telemetry IoT Hub Test Utility ===");
+ Console.WriteLine($"Publisher started. Streaming every {publisher.Config.HistorySourcesRequestInterval.TotalSeconds} seconds.");
+ Console.WriteLine("Press any key to stop streaming data...");
+
+ Console.ReadKey();
+
+ Console.WriteLine("Disposing publisher...");
+ publisher.Dispose();
+ }
+
+ private static void Publisher_PublishResultAvailable(object sender, TelemetryPublishResultAvailableEventArgs e)
+ {
+ Console.ForegroundColor = ConsoleColor.DarkGray;
+ Console.WriteLine($"Package publish result available:\n{e.PublishResult.ToString()}");
+
+ if (e.PublishResult.DestinationsResults.Any(d => d.Status == TelemetryPublishResult.DestinationStatus.Failed))
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine("One or more destinations failed to receive the package.");
+ }
+ else
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("Package successfully published.");
+ }
+ Console.ResetColor();
+
+ Console.WriteLine("Press any key to stop streaming data...");
+ }
+ }
+
+ [TelemetryName("JobRun")]
+ public class JobRunTestTelemetry : TelemetryBase
+ {
+ public String JobName { get; set; }
+ public String Thread { get; set; }
+ public double Length { get; set; }
+ }
+
+ public class JobRunsTestSource : ITelemetryHistorySource
+ {
+ private int counter = 1;
+
+ public string Name { get; } = "Persons Source";
+ public bool RequiresTelemetryDuplicationTracking { get; } = false;
+
+ public Task<bool> CanRequestHistory(DateTime from)
+ {
+ return Task.FromResult(true);
+ }
+
+ public void Dispose()
+ {
+
+ }
+
+ public Task<IEnumerable<ITelemetry>> RequestHistory(DateTime from)
+ {
+ return Task.
+ FromResult<IEnumerable<ITelemetry>>(new List<JobRunTestTelemetry>()
+ {
+ new JobRunTestTelemetry()
+ {
+ Time = DateTime.UtcNow,
+ JobName = $"Job For Materialized {counter++}",
+ Length = 1000 + counter,
+ Thread = $"Coats Thread {counter}"
+ }
+ });
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..dc1b052d1
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Tango.Telemetry.Tester.IOT.CLI")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tango.Telemetry.Tester.IOT.CLI")]
+[assembly: AssemblyCopyright("Copyright © 2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c891b2f7-e63a-40e2-b6ce-a22a69b4d86a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Tango.Telemetry.Tester.IOT.CLI.csproj b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Tango.Telemetry.Tester.IOT.CLI.csproj
new file mode 100644
index 000000000..0449a67fe
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/Tango.Telemetry.Tester.IOT.CLI.csproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{C891B2F7-E63A-40E2-B6CE-A22A69B4D86A}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Tango.Telemetry.Tester.IOT.CLI</RootNamespace>
+ <AssemblyName>Tango.Telemetry.Tester.IOT.CLI</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="DotNetty.Buffers, Version=0.4.6.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\DotNetty.Buffers.0.4.6\lib\net45\DotNetty.Buffers.dll</HintPath>
+ </Reference>
+ <Reference Include="DotNetty.Codecs, Version=0.4.6.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\DotNetty.Codecs.0.4.6\lib\net45\DotNetty.Codecs.dll</HintPath>
+ </Reference>
+ <Reference Include="DotNetty.Codecs.Mqtt, Version=0.4.6.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\DotNetty.Codecs.Mqtt.0.4.6\lib\net45\DotNetty.Codecs.Mqtt.dll</HintPath>
+ </Reference>
+ <Reference Include="DotNetty.Common, Version=0.4.6.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\DotNetty.Common.0.4.6\lib\net45\DotNetty.Common.dll</HintPath>
+ </Reference>
+ <Reference Include="DotNetty.Handlers, Version=0.4.6.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\DotNetty.Handlers.0.4.6\lib\net45\DotNetty.Handlers.dll</HintPath>
+ </Reference>
+ <Reference Include="DotNetty.Transport, Version=0.4.6.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\DotNetty.Transport.0.4.6\lib\net45\DotNetty.Transport.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Azure.Amqp, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Azure.Amqp.2.0.6\lib\net45\Microsoft.Azure.Amqp.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Azure.Devices.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Azure.Devices.Client.1.6.0\lib\net45\Microsoft.Azure.Devices.Client.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Azure.Devices.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Azure.Devices.Shared.1.3.0\lib\net45\Microsoft.Azure.Devices.Shared.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Azure.KeyVault.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Data.Edm, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Data.OData, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Data.Services.Client, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.1.0\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Logging, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Logging.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8\Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.WindowsAzure.Storage, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\WindowsAzure.Storage.7.0.0\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
+ <Reference Include="PCLCrypto, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d4421c8a4786956c, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\PCLCrypto.2.0.147\lib\net45\PCLCrypto.dll</HintPath>
+ </Reference>
+ <Reference Include="PInvoke.BCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\PInvoke.BCrypt.0.3.2\lib\net40\PInvoke.BCrypt.dll</HintPath>
+ </Reference>
+ <Reference Include="PInvoke.Kernel32, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\PInvoke.Kernel32.0.3.2\lib\net40\PInvoke.Kernel32.dll</HintPath>
+ </Reference>
+ <Reference Include="PInvoke.NCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\PInvoke.NCrypt.0.3.2\lib\net40\PInvoke.NCrypt.dll</HintPath>
+ </Reference>
+ <Reference Include="PInvoke.Windows.Core, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\PInvoke.Windows.Core.0.3.2\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
+ </Reference>
+ <Reference Include="System.ComponentModel.Composition" />
+ <Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Core" />
+ <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
+ </Reference>
+ <Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
+ </Reference>
+ <Reference Include="System.IO.Compression.FileSystem" />
+ <Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
+ </Reference>
+ <Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
+ </Reference>
+ <Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Numerics" />
+ <Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Spatial, Version=5.6.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
+ </Reference>
+ <Reference Include="Validation, Version=2.2.0.0, Culture=neutral, PublicKeyToken=2fc06f0d701809a7, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Telemetry\Tango.Telemetry.csproj">
+ <Project>{af593663-d4e9-4a14-a3f2-fea57f30e9e6}</Project>
+ <Name>Tango.Telemetry</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/packages.config b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/packages.config
new file mode 100644
index 000000000..8dabdb1c2
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.Telemetry.Tester.IOT.CLI/packages.config
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="DotNetty.Buffers" version="0.4.6" targetFramework="net461" />
+ <package id="DotNetty.Codecs" version="0.4.6" targetFramework="net461" />
+ <package id="DotNetty.Codecs.Mqtt" version="0.4.6" targetFramework="net461" />
+ <package id="DotNetty.Common" version="0.4.6" targetFramework="net461" />
+ <package id="DotNetty.Handlers" version="0.4.6" targetFramework="net461" />
+ <package id="DotNetty.Transport" version="0.4.6" targetFramework="net461" />
+ <package id="EnterpriseLibrary.TransientFaultHandling" version="6.0.1304.0" targetFramework="net461" />
+ <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net461" />
+ <package id="Microsoft.Azure.Amqp" version="2.0.6" targetFramework="net461" />
+ <package id="Microsoft.Azure.Devices.Client" version="1.6.0" targetFramework="net461" />
+ <package id="Microsoft.Azure.Devices.Shared" version="1.3.0" targetFramework="net461" />
+ <package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net461" />
+ <package id="Microsoft.Data.Edm" version="5.6.4" targetFramework="net461" />
+ <package id="Microsoft.Data.OData" version="5.6.4" targetFramework="net461" />
+ <package id="Microsoft.Data.Services.Client" version="5.6.4" targetFramework="net461" />
+ <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="1.1.0" targetFramework="net461" />
+ <package id="Microsoft.Extensions.Logging" version="1.1.1" targetFramework="net461" />
+ <package id="Microsoft.Extensions.Logging.Abstractions" version="1.1.1" targetFramework="net461" />
+ <package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net461" />
+ <package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="NETStandard.Library" version="1.6.1" targetFramework="net461" />
+ <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
+ <package id="PCLCrypto" version="2.0.147" targetFramework="net461" />
+ <package id="PInvoke.BCrypt" version="0.3.2" targetFramework="net461" />
+ <package id="PInvoke.Kernel32" version="0.3.2" targetFramework="net461" />
+ <package id="PInvoke.NCrypt" version="0.3.2" targetFramework="net461" />
+ <package id="PInvoke.Windows.Core" version="0.3.2" targetFramework="net461" />
+ <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
+ <package id="System.Collections" version="4.3.0" targetFramework="net461" />
+ <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
+ <package id="System.ComponentModel" version="4.3.0" targetFramework="net461" />
+ <package id="System.Console" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
+ <package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net461" />
+ <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
+ <package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
+ <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="System.Linq" version="4.3.0" targetFramework="net461" />
+ <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Net.Http" version="4.3.0" targetFramework="net461" />
+ <package id="System.Net.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
+ <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
+ <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
+ <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.Handles" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
+ <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
+ <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
+ <package id="System.Spatial" version="5.6.4" targetFramework="net461" />
+ <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
+ <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
+ <package id="System.Threading.Timer" version="4.3.0" targetFramework="net461" />
+ <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
+ <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
+ <package id="Validation" version="2.2.8" targetFramework="net461" />
+ <package id="WindowsAzure.Storage" version="7.0.0" targetFramework="net461" />
+</packages> \ No newline at end of file
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/App.config b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/App.config
new file mode 100644
index 000000000..c248eaa70
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/App.config
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+ </startup>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Azure.Amqp" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-2.4.0.0" newVersion="2.4.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-8.7.0.0" newVersion="8.7.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="DotNetty.Codecs.Mqtt" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="DotNetty.Handlers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/DatabaseHelper.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/DatabaseHelper.cs
new file mode 100644
index 000000000..60791a5d8
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/DatabaseHelper.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public class DatabaseHelper
+ {
+ public static void ClearTelemetryDatabase()
+ {
+ string appName = AppDomain.CurrentDomain.FriendlyName.Replace(".exe", "");
+ string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Telemetry");
+ string file = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Telemetry", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName) + ".telemetry");
+ string logFile = Path.Combine(path, appName + "-log.telemetry");
+ string backup = file + ".bak";
+
+ try
+ {
+ if (File.Exists(file)) File.Delete(file);
+ if (File.Exists(backup)) File.Delete(backup);
+ if (File.Exists(logFile)) File.Delete(logFile);
+ Logger.LogWarning("Cleaned telemetry database for fresh test run.");
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"Failed to clear telemetry database: {ex.Message}");
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Logger.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Logger.cs
new file mode 100644
index 000000000..8490ccfc6
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Logger.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public static class Logger
+ {
+ public static void LogInfo(String message)
+ {
+ Console.ForegroundColor = ConsoleColor.White;
+ Console.WriteLine(message);
+ }
+
+ public static void LogWarning(String message)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine(message);
+ }
+
+ public static void LogError(String message)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine(message);
+ }
+
+ public static void LogSuccess(String message)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine(message);
+ }
+
+ public static void LogVerbose(String message)
+ {
+ Console.ForegroundColor = ConsoleColor.Gray;
+ Console.WriteLine(message);
+ }
+
+ public static void LogVerboseByLogManager(String message)
+ {
+ Console.ForegroundColor = ConsoleColor.DarkGray;
+ Console.WriteLine(message);
+ }
+
+ public static void LogTitle(string title)
+ {
+ Console.ForegroundColor = ConsoleColor.Cyan;
+ Console.WriteLine($"\n===== {title} =====");
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockCheckpointsRecoveryClient.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockCheckpointsRecoveryClient.cs
new file mode 100644
index 000000000..82b7d739f
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockCheckpointsRecoveryClient.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Tango.Telemetry;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public class MockCheckpointsRecoveryClient : ITelemetryCheckpointsRecoveryClient
+ {
+ public Task<List<TelemetryHistorySourceCheckPoint>> GetCheckpointsBackup() => Task.FromResult(new List<TelemetryHistorySourceCheckPoint>());
+ public Task SaveCheckpointsBackup(List<TelemetryHistorySourceCheckPoint> checkPoints) => Task.CompletedTask;
+ public void Dispose() { }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockDestinationWithFailure.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockDestinationWithFailure.cs
new file mode 100644
index 000000000..400dbf3ef
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockDestinationWithFailure.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Tango.Telemetry;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public class MockDestinationWithFailure : ITelemetryDestination
+ {
+ public string Name { get; set; }
+ public List<string> ReceivedPayloads { get; } = new List<string>();
+ public int FailCountRemaining { get; private set; }
+ public int TotalAttempts { get; private set; } = 0;
+
+ public MockDestinationWithFailure(string name, int failCount)
+ {
+ Name = name;
+ FailCountRemaining = failCount;
+ }
+
+ public IReadOnlyList<TelemetrySourceTypes> SupportedSourceTypes => new[]
+ {
+ TelemetrySourceTypes.Streaming,
+ TelemetrySourceTypes.ExternalStorage,
+ TelemetrySourceTypes.PendingStorage
+ };
+
+ public Task<bool> IsAvailable() => Task.FromResult(true);
+
+ public Task Publish(TelemetryPublishPackage package, List<KeyValuePair<string, string>> properties)
+ {
+ TotalAttempts++;
+ if (FailCountRemaining-- > 0)
+ {
+ throw new Exception("Simulated publish failure");
+ }
+
+ var payload = package.ToPayload();
+ ReceivedPayloads.Add(payload);
+ Logger.LogInfo($"Destination '{Name}' received payload: {payload}");
+ return Task.CompletedTask;
+ }
+
+ public void Dispose() { }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockHistorySource.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockHistorySource.cs
new file mode 100644
index 000000000..6ecd7e637
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockHistorySource.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Tango.Telemetry;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public class MockHistorySource : ITelemetryHistorySource
+ {
+ public string Name { get; }
+
+ public int ProvidedCount { get; set; }
+
+ public MockHistorySource(string name)
+ {
+ Name = name;
+ }
+
+ public Task<bool> CanRequestHistory(DateTime from) => Task.FromResult(true);
+
+ public Task<IEnumerable<ITelemetry>> RequestHistory(DateTime from)
+ {
+ Logger.LogInfo($"[HistorySource] Providing historical telemetry at {DateTime.UtcNow}");
+
+ ProvidedCount++;
+
+ return Task.FromResult<IEnumerable<ITelemetry>>(new[]
+ {
+ new MockTelemetry { Time = DateTime.UtcNow.AddSeconds(-30) }
+ });
+ }
+
+ public void Dispose() { }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockStreamingSource.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockStreamingSource.cs
new file mode 100644
index 000000000..0ca058ec9
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockStreamingSource.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Threading;
+using Tango.Telemetry;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public class MockStreamingSource : ITelemetryStreamingSource
+ {
+ public string Name { get; }
+ public event EventHandler<TelemetryAvailableEventArgs> TelemetryAvailable;
+ private Timer _timer;
+ public int EmittedCount { get; private set; }
+ private bool _isStarted = false;
+
+ public MockStreamingSource(string name)
+ {
+ Name = name;
+ }
+
+ public void Start()
+ {
+ if (_isStarted) return;
+ _isStarted = true;
+ _timer = new Timer(SendTelemetry, null, 500, 1000);
+ }
+
+ public void Stop()
+ {
+ if (!_isStarted) return;
+ _timer?.Dispose();
+ _timer = null;
+ _isStarted = false;
+ }
+
+ private void SendTelemetry(object state)
+ {
+ var telemetry = new MockTelemetry { Time = DateTime.UtcNow };
+ EmittedCount++;
+ Logger.LogVerbose($"Emitting telemetry #{EmittedCount} from {Name}");
+ TelemetryAvailable?.Invoke(this, new TelemetryAvailableEventArgs(telemetry, TelemetrySourceTypes.Streaming));
+ }
+
+ public void Dispose() => Stop();
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockTelemetry.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockTelemetry.cs
new file mode 100644
index 000000000..fb96e5819
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/MockTelemetry.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Text;
+using Tango.Telemetry;
+
+namespace Tango.TelemetryTester.CLI
+{
+ public class MockTelemetry : ITelemetry
+ {
+ public DateTime Time { get; set; }
+
+ public string ToJson(Newtonsoft.Json.Formatting format = Newtonsoft.Json.Formatting.None, bool flatten = true)
+ {
+ return $"{{\"time\": \"{Time:o}\"}}";
+ }
+
+ public byte[] ToBytes(Newtonsoft.Json.Formatting format = Newtonsoft.Json.Formatting.None, bool flatten = true)
+ {
+ return Encoding.UTF8.GetBytes(ToJson(format, flatten));
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Program.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Program.cs
new file mode 100644
index 000000000..1b985e35b
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Program.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using Tango.BL.Enumerations;
+using Tango.Logging;
+using Tango.Telemetry;
+
+namespace Tango.TelemetryTester.CLI
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Run().GetAwaiter().GetResult();
+ }
+
+ static async Task Run()
+ {
+ Logger.LogTitle("Telemetry Pipeline Test Starting...");
+ DatabaseHelper.ClearTelemetryDatabase();
+
+ LogManager.Default.NewLog += (x, log) =>
+ {
+ switch (log.Category)
+ {
+ case LogCategory.Info:
+ case LogCategory.Debug:
+ Logger.LogVerboseByLogManager(log.Message);
+ break;
+ case LogCategory.Warning:
+ Logger.LogWarning(log.Message);
+ break;
+ case LogCategory.Error:
+ case LogCategory.Critical:
+ Logger.LogError(log.Message);
+ break;
+ }
+ };
+
+ var config = new TelemetryPublisherConfiguration
+ {
+ SerialNumber = "TEST-MACHINE",
+ MachineType = MachineTypes.TS1800,
+ Environment = "DEV",
+ PendingStorageCheckInterval = TimeSpan.FromSeconds(5),
+ HistorySourcesRequestInterval = TimeSpan.FromSeconds(5)
+ };
+
+ var recoveryClient = new MockCheckpointsRecoveryClient();
+ var publisher = new TelemetryPublisher(config, recoveryClient);
+
+ var mockStreamingSource = new MockStreamingSource("MockStreamingSource1");
+ var mockHistorySource = new MockHistorySource("MockHistorySource1");
+ var destination1 = new MockDestinationWithFailure("MockDestination", failCount: 2);
+ var destination2 = new MockDestinationWithFailure("FastDestination", failCount: 0);
+ var destination3 = new MockDestinationWithFailure("HistoryOnlyDestination", failCount: 0);
+
+ publisher.RegisterSource(mockStreamingSource);
+ publisher.RegisterSource(mockHistorySource);
+ publisher.RegisterDestination(destination1);
+ publisher.RegisterDestination(destination2);
+ publisher.RegisterDestination(destination3);
+
+ var results = new List<string>();
+ var publishCount = 0;
+ var failureCount = 0;
+
+ publisher.PackagePublished += (s, e) =>
+ {
+ publishCount++;
+ var msg = $"SUCCESS: published telemetry to {e.Destination.Name}";
+ results.Add(msg);
+ Logger.LogSuccess(msg);
+ };
+
+ publisher.PublishPackageFailed += (s, e) =>
+ {
+ failureCount++;
+ var msg = $"FAILURE: failed to publish telemetry to {e.Destination.Name} - {e.Exception.Message}";
+ results.Add(msg);
+ Logger.LogError(msg);
+ };
+
+ await publisher.Start();
+ await Task.Delay(7000);
+ await publisher.Stop();
+
+ int pendingCount = publisher.StorageManager.GetPendingTelemetriesCount();
+
+ Logger.LogTitle("TEST REPORT");
+ Logger.LogInfo($"Total telemetry generated by streaming source: {mockStreamingSource.EmittedCount}");
+ Logger.LogInfo($"Total telemetry generated by history source: {mockHistorySource.ProvidedCount}");
+ Logger.LogInfo($"Total failures (intentional): {failureCount}");
+ Logger.LogInfo($"Total payloads received by MockDestination: {destination1.ReceivedPayloads.Count}");
+ Logger.LogInfo($"Total payloads received by FastDestination: {destination2.ReceivedPayloads.Count}");
+ Logger.LogInfo($"Total payloads received by HistoryOnlyDestination: {destination3.ReceivedPayloads.Count}");
+ Logger.LogInfo($"Total telemetries published: {publishCount}");
+
+ int totalExpectedPublishes = (mockStreamingSource.EmittedCount + mockHistorySource.ProvidedCount) * 3;
+ bool allEmittedPublished = publishCount == totalExpectedPublishes;
+ bool allPublishedReceived = publishCount == destination1.ReceivedPayloads.Count + destination2.ReceivedPayloads.Count + destination3.ReceivedPayloads.Count;
+ bool retriesOccurred = destination1.TotalAttempts > destination1.ReceivedPayloads.Count;
+ bool noPendingLeft = pendingCount == 0;
+
+ Logger.LogTitle("TEST VERDICT");
+ Logger.LogInfo(allEmittedPublished ? "PASS: Emitted telemetry all published" : "FAIL: Emitted telemetry not fully published");
+ Logger.LogInfo(allPublishedReceived ? "PASS: All published telemetry received by destinations" : "FAIL: Some published telemetry was not received");
+ Logger.LogInfo(retriesOccurred ? "PASS: Retry logic triggered and succeeded" : "FAIL: Retry logic did not activate as expected");
+ Logger.LogInfo(noPendingLeft ? "PASS: Pending storage clean after test" : $"FAIL: {pendingCount} telemetry still pending in storage");
+
+ Logger.LogTitle("DETAILED EVENTS");
+ foreach (var line in results)
+ Logger.LogInfo(line);
+
+ Logger.LogSuccess("\nTest complete.");
+ Console.ReadKey();
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..e4666e75a
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Tango.TelemetryTester.CLI")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tango.TelemetryTester.CLI")]
+[assembly: AssemblyCopyright("Copyright © 2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("db3a1470-994b-46df-9be8-f905cdb97a3a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Tango.TelemetryTester.CLI.csproj b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Tango.TelemetryTester.CLI.csproj
new file mode 100644
index 000000000..cc4ba9298
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Tango.TelemetryTester.CLI.csproj
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{DB3A1470-994B-46DF-9BE8-F905CDB97A3A}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Tango.TelemetryTester.CLI</RootNamespace>
+ <AssemblyName>Tango.TelemetryTester.CLI</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="DatabaseHelper.cs" />
+ <Compile Include="Logger.cs" />
+ <Compile Include="MockCheckpointsRecoveryClient.cs" />
+ <Compile Include="MockDestinationWithFailure.cs" />
+ <Compile Include="MockHistorySource.cs" />
+ <Compile Include="MockStreamingSource.cs" />
+ <Compile Include="MockTelemetry.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ <None Include="packages.config" />
+ <None Include="Verifications List.md" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Tango.BL\Tango.BL.csproj">
+ <Project>{f441feee-322a-4943-b566-110e12fd3b72}</Project>
+ <Name>Tango.BL</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Core\Tango.Core.csproj">
+ <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project>
+ <Name>Tango.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Logging\Tango.Logging.csproj">
+ <Project>{bc932dbd-7cdb-488c-99e4-f02cf441f55e}</Project>
+ <Name>Tango.Logging</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Tango.Telemetry\Tango.Telemetry.csproj">
+ <Project>{af593663-d4e9-4a14-a3f2-fea57f30e9e6}</Project>
+ <Name>Tango.Telemetry</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Verifications List.md b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Verifications List.md
new file mode 100644
index 000000000..90362d659
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/Verifications List.md
@@ -0,0 +1,90 @@
+### ✅ **Basic Functional Verifications**
+
+1. **Source Trigger Verification**
+
+ * Log a message every time `MockStreamingSource` generates a telemetry.
+ * Count how many times `TelemetryAvailable` was raised vs. published.
+
+2. **Destination Receipt Check**
+
+ * Confirm each destination receives telemetry that matches the `ToPayload()` value.
+ * Add internal counters per destination to confirm delivery.
+
+3. **Package Identity Tracking**
+
+ * Assign a unique ID to each telemetry object and verify that:
+
+ * It travels all the way to the destination.
+ * It is not duplicated or lost.
+
+---
+
+### 🔁 **Retry and Backoff Testing**
+
+4. **Destination Retry Logic**
+
+ * Simulate a failure in `MockDestination.Publish()` every Nth call.
+ * Verify that retries are scheduled with exponential backoff.
+
+5. **Pending Storage Write/Read**
+
+ * Cause all destinations to fail.
+ * Confirm that telemetry is persisted to `TelemetryLiteDBStorageManager`.
+ * Manually inspect `PendingTelemetries.Count` after the run.
+
+---
+
+### 🕒 **Time & Latency Metrics**
+
+6. **Elapsed Time Per Publish**
+
+ * Log how long it takes from package creation to successful publish.
+
+7. **Latency Bucketing**
+
+ * Track telemetry latency buckets (e.g., `<1s`, `1–5s`, `>5s`) and print histogram.
+
+---
+
+### 📦 **Historical and Pending Telemetry**
+
+8. **History Source Verification**
+
+ * Confirm `MockHistorySource.RequestHistory()` is triggered periodically.
+ * Verify telemetry from it is published and updated in checkpoints.
+
+9. **Checkpoint Verification**
+
+ * Track when and how often checkpoints are updated.
+ * Ensure they persist across runs using `TelemetryLiteDBStorageManager`.
+
+---
+
+### 🛠️ **Fault Injection and Resilience**
+
+10. **Out-of-Order Timestamps**
+
+ * Send telemetry with past/future timestamps and check ordering in publish results.
+
+11. **Multiple Concurrent Sources**
+
+ * Add 2–3 `MockStreamingSource` instances and confirm the system handles interleaved input.
+
+12. **Slow Publisher Simulation**
+
+ * Simulate slow or blocking destination publish methods.
+ * Confirm queue doesn’t overflow and telemetry is not lost.
+
+---
+
+### 🧪 **Extended Diagnostic Reporting**
+
+13. **Final Report Enhancements**
+
+ * Total telemetry generated, published, failed, retried, and persisted.
+ * Telemetry per source/destination.
+ * Count of `TelemetryAvailable` vs `Publish()`.
+
+---
+
+Would you like to start with a few of these now? I can help you implement fault injection, persistence inspection, or anything else you choose.
diff --git a/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/packages.config b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/packages.config
new file mode 100644
index 000000000..7ee8c1052
--- /dev/null
+++ b/Software/Visual_Studio/Utilities/Tango.TelemetryTester.CLI/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
+</packages> \ No newline at end of file