/*
* Copyright (c) 2024 Proton AG
*
* This file is part of ProtonVPN.
*
* ProtonVPN is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonVPN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonVPN. If not, see .
*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using FlaUI.Core.Tools;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
namespace ProtonVPN.UI.Tests.TestsHelper;
public class SliHelper
{
public static string? SliName { get; set; }
public static string? Workflow { get; set; }
public static string? RunId { get; set; }
public static readonly Stopwatch Timer = new();
public static List MetricsList = [];
private static bool IsMonitoring { get; set; }
private static double Duration => Timer.Elapsed.TotalSeconds;
public static void MeasureTime(Action method)
{
Timer.Start();
IsMonitoring = true;
method();
Timer.Stop();
IsMonitoring = false;
}
public static void MeasureTestStatus(Action method)
{
IsMonitoring = true;
method();
IsMonitoring = false;
}
public static void Reset()
{
Timer.Reset();
MetricsList.Clear();
}
public static void AddMetric(string metricName, string value)
{
MetricsList.Add(new JProperty(metricName, value));
}
public static void AddDuration()
{
if (Duration != 0)
{
AddMetric("duration", Duration.ToString());
}
}
public static void AddTestStatusMetric()
{
TestStatus status = TestContext.CurrentContext.Result.Outcome.Status;
if (status == TestStatus.Passed)
{
AddMetric("status", "passed");
}
else if (IsMonitoring && status == TestStatus.Failed)
{
AddMetric("status", "failed");
}
}
public static void AddNetworkSpeedToMetrics(string downloadSpeedLabel, string uploadSpeedLabel)
{
DnsHelper.FlushDns();
Dictionary? networkSpeedConnected = null;
RetryResult retry = Retry.WhileException(
() =>
{
networkSpeedConnected = GetNetworkSpeed();
},
TestConstants.ThirtySecondsTimeout, TestConstants.ApiRetryInterval);
if (!retry.Success)
{
throw new Exception(retry.LastException?.Message);
}
AddMetric(downloadSpeedLabel, networkSpeedConnected?["downloadSpeed"].ToString() ?? string.Empty);
AddMetric(uploadSpeedLabel, networkSpeedConnected?["uploadSpeed"].ToString() ?? string.Empty);
}
public static Dictionary GetNetworkSpeed()
{
Dictionary networkStats = new();
string speedTestPath = "speedtest.exe";
// Arguments for speedtest.exe to output in JSON format
string arguments = "--accept-gdpr --accept-license -f json ";
// Start the process
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = speedTestPath,
Arguments = arguments,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (Process? process = Process.Start(startInfo))
{
if (process != null)
{
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit(TestConstants.TenSecondsTimeout);
JObject result = JObject.Parse(output);
JToken? downloadToken = result["download"]?["bandwidth"];
JToken? uploadToken = result["upload"]?["bandwidth"];
if (downloadToken is null || uploadToken is null)
{
throw new InvalidOperationException("Speedtest output missing required bandwidth fields.");
}
double downloadSpeedInBytes = (double)downloadToken;
double downloadSpeedInMbps = ConvertBytesToMbps(downloadSpeedInBytes);
double uploadSpeedInBytes = (double)uploadToken;
double uploadSpeedInMbps = ConvertBytesToMbps(uploadSpeedInBytes);
networkStats.Add("downloadSpeed", downloadSpeedInMbps);
networkStats.Add("uploadSpeed", uploadSpeedInMbps);
}
else
{
Console.WriteLine("Failed to start speedtest.exe process.");
}
}
return networkStats;
}
private static double ConvertBytesToMbps(double valueInBytes)
{
return (valueInBytes * 8) / 1000000;
}
}