// TARGET:chrome.exe -incognito --force-renderer-accessibility "https://octane.webmarks.info/" // START_IN: using LoginPI.Engine.ScriptBase; using System; using System.IO; using System.Diagnostics; using System.Text.RegularExpressions; using System.Collections.Generic; using System.Text; using System.Globalization; using LoginPI.Engine.ScriptBase.Components; /// SCRIPT TESTED ON 11/19/24 using Chrome 131.0.6778.70 and Edge 131.0.2903.51 /// /* chrome.exe -incognito --force-renderer-accessibility "https://octane.webmarks.info/" msedge.exe -inPrivate --force-renderer-accessibility "https://octane.webmarks.info/" */ /// public class Octane2 : ScriptBase { // Variables for PowerShell script string timeOffset = "0:00"; // Time offset in hours:minutes (e.g., "-7:00" for PST, "+7:00" or "7:00" for UTC+7). The Login Enterprise API only accepts Zulu ISO 8601 timestamps, so this can be used to adjust the timestamps to the correct time zone. string configurationAccessToken = ""; // Your configuration access token here. To create one log into the Login Enterprise web interface -> External notifications -> Public API -> New system access token -> provide a name for the token -> select Configuration from the Access-level drop-down -> Save -> in the new popup copy out the token and put here in this configurationAccessToken variable. Ensure to store the token elsewhere securely. string baseUrl = "https://"; // Your base Login Enterprise URL here including the ending slash. For example: https://myLoginEnterprise.myDomain.com/ /// SET YOUR ENVIRONMENT BY ID HERE...BE CAREFUL TO CHECK THIS BEFORE RUNNING YOUR SCRIPT, EVEN IN THE SCRIPT EDITOR string environmentId = ""; // Your environment key/ID here. To get an environment ID to put here: log into the Login Enterprise web interface -> Environments -> Open the Environment to use -> at the end of the address bar of the browser find the environment unique ID, for example: 3221ce29-06ba-46a2-8c8b-da99dea341c4. Or create a new Environment in the Environments page -> Add environment -> fill out needed information in this page (but only Name is needed) -> Save -> the unique Environment ID will be at the end of the address bar // store temp GUIDs here used for any testing... string apiEndpoint = "/publicApi/v7-preview/platform-metrics"; // API Endpoint string powershellScriptPath = "temp"; // Path to save the PowerShell script ("temp" for default temporary path) string tempScriptFile; // Paths to temporary files used in PowerShell script execution string payloadFilePath; string tempResultsDir; List BenchmarkDataList = new List(); string computerName; string processName; int standardTimeout = 30; int waitForOctaneToComplete = 120; string octaneMultiScore; string octaneScore; bool chrome; bool edge; void Execute() { computerName = GetEnvironmentVariable("COMPUTERNAME"); string temp = GetEnvironmentVariable("TEMP"); string tempLoginPI = Path.Combine(temp, "LoginPI"); tempResultsDir = Path.Combine(tempLoginPI, "Results"); if (!DirectoryExists(tempResultsDir)) { Directory.CreateDirectory(tempResultsDir); } else { Log("Directory already existed..."); } payloadFilePath = Path.Combine(tempResultsDir, "payload.json"); tempScriptFile = Path.Combine(tempResultsDir, "sendPlatformMetrics.ps1"); // check for command line here, switches for chrome/edge if (CommandLine.Contains("chrome")) { processName = "chrome"; Log("Script set to run Octane via Chrome..."); } else if (CommandLine.Contains("edge")) { processName = "msedge"; Log("Script set to run Octane via Edge..."); } START(mainWindowTitle: "Octane*", processName: processName); Wait(2); MainWindow.Maximize(); // verify we reched octane page by finding the top-left logo MainWindow.FindControl(className : "Text", title : "Octane*", timeout: standardTimeout); Wait(2, showOnScreen: true, onScreenText: "Starting Octane Test"); // find and click "Start Octane 2.0 Button" var startOctaneTestBtn = MainWindow.FindControl(className: "Group*", title: "Start Octane 2.0 plus", timeout: standardTimeout); string octaneTimestamp = GetTimeNow(); startOctaneTestBtn.Click(); // wait for test to complete Wait(waitForOctaneToComplete); if (processName == "msedge") { var octaneScorePane = MainWindow.FindControl(className: "Group:score-card v-card v-card--disabled v-sheet theme--dark"); var octaneScoreRaw = octaneScorePane.GetAllChildControls()[0].GetTitle(); var octaneScoreRawSplit = octaneScoreRaw.Split(' '); octaneScore = octaneScoreRawSplit[octaneScoreRawSplit.Length - 1].Trim(); var octaneMultiScorePane = MainWindow.FindControl(className: "Group:score-card v-card v-sheet theme--dark"); var octaneMultiScoreRaw = octaneMultiScorePane.GetAllChildControls()[0].GetTitle(); var octaneMultiScoreSplit = octaneMultiScoreRaw.Split(' '); octaneMultiScore = octaneMultiScoreSplit[octaneMultiScoreSplit.Length - 1].Trim(); } else if (processName == "chrome") { var resultsPane = MainWindow.FindControl(className: "Document*", title: "Chrome Legacy Window"); var resultsGroup = resultsPane.GetAllChildControls()[1]; var resultsGroupChildren = resultsGroup.GetAllChildControls(); // Group -- "" octaneScore = resultsGroupChildren[1].GetTitle().Trim(); // Text -- 'XX.XXX' octaneMultiScore = resultsGroupChildren[3].GetTitle().Trim(); // Text -- 'XXX.XXX' } Log($"Octane score was: {octaneScore}, Octane Multi Core score was: {octaneMultiScore}"); string metricGroup = "Octane 2.0"; string cleanOctaneScore = octaneScore.Replace(",", ""); try { double doubleOctaneScore = double.Parse(cleanOctaneScore); BuildBenchmarkData(metricGroup: metricGroup, metricName: "Octane Score", metricValue: doubleOctaneScore, metricUnits: "Score", metricTimestamp: octaneTimestamp); } catch (Exception e) { CreateEvent($"Could not return Octane score because {e}"); } string cleanOctaneMultiScore = octaneMultiScore.Replace(",", ""); try { double doubleOctaneMultiScore = double.Parse(cleanOctaneMultiScore); BuildBenchmarkData(metricGroup: metricGroup, metricName: "Multi Core Score", metricValue: doubleOctaneMultiScore, metricUnits: "Score", metricTimestamp: octaneTimestamp); } catch (Exception e) { CreateEvent($"Could not return Octane Multi Core score because {e}"); } MainWindow.Close(); BuildPayloadFile(); Wait(.5); BuildPowerShellScript(); Wait(.5); UploadPlatformMetricsPowerShellRunner(); Wait(.5); DoCleanup(); STOP(); } void BuildBenchmarkData(string metricGroup, string metricName, double metricValue, string metricUnits, string metricTimestamp) { var BenchmarkData = new BenchmarkData { Group = metricGroup, Name = metricName, Instance = computerName, ComponentType = processName, Value = metricValue, Units = metricUnits, TimeStamp = metricTimestamp }; BenchmarkDataList.Add(BenchmarkData); } void DoCleanup() { // Clean up the temporary files if (FileExists(tempScriptFile)) { RemoveFile(tempScriptFile); } if (FileExists(payloadFilePath)) { RemoveFile(payloadFilePath); } if (DirectoryExists(tempResultsDir)) { RemoveFolder(tempResultsDir); } } void UploadPlatformMetricsPowerShellRunner() // Run the PowerShell script to upload platform metrics { Log("Starting method: UploadPlatformMetricsPowerShellRunner"); try { ProcessStartInfo psi = new ProcessStartInfo { FileName = "powershell.exe", Arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{tempScriptFile}\"", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using (Process process = new Process()) { process.StartInfo = psi; // Event handlers to capture asynchronous output process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { Log(e.Data); } }; process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { Log("Error: " + e.Data); } }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); } } catch (Exception ex) { Log("Exception: " + ex.Message); } } void BuildPowerShellScript() { string scriptContent = $@" [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {{ $true }} $configurationAccessToken = '{configurationAccessToken}' $fullUrl = '{baseUrl}{apiEndpoint}' $payloadFile = '{payloadFilePath.Replace("\\", "\\\\")}' ### Read payload from file ### $payload = Get-Content -Path $payloadFile -Raw ### Debug: Output JSON Payload ### Write-Host 'JSON Payload:' Write-Host $payload ### Create HttpWebRequest ### $request = [System.Net.HttpWebRequest]::Create($fullUrl) $request.Method = 'POST' $request.ContentType = 'application/json' $request.Accept = 'application/json' $request.Headers.Add('Authorization', 'Bearer ' + $configurationAccessToken) # Write JSON Payload to Request Body $byteArray = [System.Text.Encoding]::UTF8.GetBytes($payload) $request.ContentLength = $byteArray.Length $requestStream = $request.GetRequestStream() $requestStream.Write($byteArray, 0, $byteArray.Length) $requestStream.Close() ### Send Request and Handle Response ### try {{ Write-Host ""$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [INFO] - Sending POST request to $fullUrl..."" $response = $request.GetResponse() $responseStream = $response.GetResponseStream() $reader = New-Object IO.StreamReader($responseStream) $responseContent = $reader.ReadToEnd() $reader.Close() Write-Host ""$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [SUCCESS] - Response received:"" Write-Host $responseContent }} catch [System.Net.WebException] {{ Write-Host ""$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [ERROR] - Error: $($_.Exception.Message)"" if ($_.Exception.Response) {{ $errorStream = $_.Exception.Response.GetResponseStream() $reader = New-Object IO.StreamReader($errorStream) $errorContent = $reader.ReadToEnd() $reader.Close() Write-Host '[ERROR] - Full HTTP Response:' Write-Host $errorContent }} }} "; // Write the PowerShell script to the specified location File.WriteAllText(tempScriptFile, scriptContent); } void BuildPayloadFile() { // Manually build the JSON payload StringBuilder payloadBuilder = new StringBuilder(); payloadBuilder.Append("["); for (int i = 0; i < BenchmarkDataList.Count; i++) { var data = BenchmarkDataList[i]; payloadBuilder.Append("{"); payloadBuilder.AppendFormat("\"metricId\":\"{0}\",", EscapeString(data.Name)); payloadBuilder.AppendFormat("\"environmentKey\":\"{0}\",", EscapeString(environmentId)); payloadBuilder.AppendFormat("\"timestamp\":\"{0}\",", EscapeString(data.TimeStamp)); payloadBuilder.AppendFormat("\"group\":\"{0}\",", EscapeString(data.Group)); payloadBuilder.AppendFormat("\"instance\":\"{0}\",", EscapeString(data.Instance)); payloadBuilder.AppendFormat("\"displayName\":\"{0}\",", EscapeString(data.Name)); payloadBuilder.AppendFormat("\"unit\":\"{0}\",", EscapeString(data.Units)); payloadBuilder.AppendFormat("\"componentType\":\"{0}\",", EscapeString(data.ComponentType)); payloadBuilder.AppendFormat("\"value\":{0}", data.Value); payloadBuilder.Append("}"); if (i < BenchmarkDataList.Count - 1) { payloadBuilder.Append(","); } } payloadBuilder.Append("]"); string payload = payloadBuilder.ToString(); // Write payload to the determined path File.WriteAllText(payloadFilePath, payload); } string GetTimeNow() { if (!TryParseTimeOffset(timeOffset, out TimeSpan offset)) { throw new Exception($"Invalid time offset format: {timeOffset}"); } // Adjust the time to UTC by subtracting the offset DateTime timeNow = DateTime.Now; DateTime utcTimeNow = timeNow - offset; string TimeNow = utcTimeNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); return TimeNow; } // Helper method to escape strings for JSON private string EscapeString(string s) { if (string.IsNullOrEmpty(s)) return ""; return s.Replace("\\", "\\\\").Replace("\"", "\\\""); } private bool TryParseTimeOffset(string timeOffsetStr, out TimeSpan offset) // Handle time offset parsing { offset = TimeSpan.Zero; if (string.IsNullOrWhiteSpace(timeOffsetStr)) return false; // Remove whitespace timeOffsetStr = timeOffsetStr.Trim(); // Handle '+' or '-' sign bool isNegative = false; if (timeOffsetStr.StartsWith("+")) { timeOffsetStr = timeOffsetStr.Substring(1); } else if (timeOffsetStr.StartsWith("-")) { isNegative = true; timeOffsetStr = timeOffsetStr.Substring(1); } // Try parsing the time offset if (TimeSpan.TryParse(timeOffsetStr, out TimeSpan parsedOffset)) { offset = isNegative ? parsedOffset.Negate() : parsedOffset; return true; } else { return false; } } // Class to store benchmark data class BenchmarkData { public string MetricId { get; set; } public string ComponentType { get; set; } public string Group { get; set; } public string Name { get; set; } // Corresponds to 'instance' in the API public string Instance { get; set; } public string Units { get; set; } public double Value { get; set; } // Corresponds to 'value' in the API public string TimeStamp { get; set; } // Original timestamp //public string IsoTimeStamp { get; set; } // Adjusted to UTC and formatted in ISO 8601 } }