/// <summary>
        /// Initializes a new instance of the <see cref="AgentClient"/> class.
        /// </summary>
        /// <param name="remoteAddress">The remote address where the Agent is running.</param>
        /// <param name="token">The development token used to authenticate with the Agent.</param>
        /// <param name="capabilities">Requested driver options for the browser session.</param>
        /// <param name="reportSettings">Contains the project and job name to report to TestProject.</param>
        /// <param name="disableReports">Set to true to disable all reporting to TestProject, false otherwise.</param>
        /// <param name="compatibleVersion">Minimum Agent version that supports the requested feature. Can be used to check Agent compatibility.</param>
        private AgentClient(Uri remoteAddress, string token, DriverOptions capabilities, ReportSettings reportSettings, bool disableReports, Version compatibleVersion)
        {
            this.remoteAddress = this.InferRemoteAddress(remoteAddress);

            ReportSettings sessionReportSettings = disableReports ? null : this.InferReportSettings(reportSettings);

            if (token != null)
            {
                this.token = token;
            }
            else if (Environment.GetEnvironmentVariable(this.tpDevToken) != null)
            {
                this.token = Environment.GetEnvironmentVariable(this.tpDevToken);
            }
            else
            {
                throw new InvalidTokenException("No token has been provided.");
            }

            this.client = new RestClient(this.remoteAddress);
            this.client.AddDefaultHeader("Authorization", this.token);

            this.serializerSettings = CustomJsonSerializer.Populate(new JsonSerializerSettings());

            // Check that Agent version supports the requested feature.
            if (compatibleVersion != null)
            {
                Logger.Trace($"Checking if the Agent version is {compatibleVersion} at minimum");

                this.agentVersion = this.GetAgentVersion();

                // a.CompareTo(b) returns:
                // * <0 if a is earlier than b
                // *  0 if a is the same version as b
                // * >0 is a is later than b
                if (this.agentVersion.CompareTo(compatibleVersion) < 0)
                {
                    throw new AgentConnectException($"Current Agent version {this.agentVersion} does not support the requested feature," +
                                                    $" should be at least {compatibleVersion}");
                }
            }

            this.reportsQueue = new ReportsQueue(this.client);

            this.StartSession(sessionReportSettings, capabilities);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="AgentClient"/> class.
        /// </summary>
        /// <param name="remoteAddress">The remote address where the Agent is running.</param>
        /// <param name="token">The development token used to authenticate with the Agent.</param>
        /// <param name="capabilities">Requested driver options for the browser session.</param>
        /// <param name="reportSettings">Contains the project and job name to report to TestProject.</param>
        /// <param name="disableReports">Set to true to disable all reporting to TestProject, false otherwise.</param>
        /// <param name="compatibleVersion">Minimum Agent version that supports the requested feature. Can be used to check Agent compatibility.</param>
        private AgentClient(Uri remoteAddress, string token, DriverOptions capabilities, ReportSettings reportSettings, bool disableReports, Version compatibleVersion = null)
        {
            this.remoteAddress = this.InferRemoteAddress(remoteAddress);

            ReportSettings sessionReportSettings = disableReports ? null : this.InferReportSettings(reportSettings);

            this.reportSettings = sessionReportSettings;

            if (token != null)
            {
                this.token = token;
            }
            else if (Environment.GetEnvironmentVariable(this.tpDevToken) != null)
            {
                this.token = Environment.GetEnvironmentVariable(this.tpDevToken);
            }
            else
            {
                throw new InvalidTokenException("No token has been provided.");
            }

            this.client = new RestClient(this.remoteAddress);
            this.client.AddDefaultHeader("Authorization", this.token);

            this.serializerSettings = CustomJsonSerializer.Populate(new JsonSerializerSettings());

            // Check that Agent version supports the requested feature.
            if (compatibleVersion != null)
            {
                Logger.Trace($"Checking if the Agent version is {compatibleVersion} at minimum");

                agentVersion = this.GetAgentVersion();

                if (agentVersion.CompareTo(compatibleVersion) < 0)
                {
                    throw new AgentConnectException($"Current Agent version {agentVersion} does not support the requested feature," +
                                                    $" should be at least {compatibleVersion}");
                }
            }

            this.reportsQueue = new ReportsQueue(this.client);

            this.StartSession(sessionReportSettings, capabilities);

            // Verify the agent version supports local report generation
            this.VerifyIfLocalReportsIsSupported(reportSettings.ReportType);

            // Show local report path only when executing on local agents.
            if (this.client.BaseUrl.IsLocal())
            {
                Logger.Info($"Execution Report: {this.sessionResponse.LocalReport}");
            }

            if (!string.IsNullOrWhiteSpace(this.sessionResponse.LocalReportUrl))
            {
                Logger.Info($"Execution Report Link: {this.sessionResponse.LocalReportUrl}");
            }
        }
        /// <summary>
        /// If necessary, creates and then returns a singleton instance of the <see cref="AgentClient"/>.
        /// </summary>
        /// <param name="remoteAddress">The remote address where the Agent is running.</param>
        /// <param name="token">The development token used to authenticate with the Agent.</param>
        /// <param name="capabilities">Requested driver options for the browser session.</param>
        /// <param name="reportSettings">Contains the project and job name to report to TestProject.</param>
        /// <param name="disableReports">Set to true to disable all reporting to TestProject, false otherwise.</param>
        /// <param name="compatibleVersion">Minimum Agent version that supports the requested feature. Can be used to check Agent compatibility.</param>
        /// <returns>A singleton instance of the <see cref="AgentClient"/>.</returns>
        public static AgentClient GetInstance(Uri remoteAddress, string token, DriverOptions capabilities, ReportSettings reportSettings, bool disableReports, Version compatibleVersion = null)
        {
            if (instance == null)
            {
                instance = new AgentClient(remoteAddress, token, capabilities, reportSettings, disableReports, compatibleVersion);
            }

            return(instance);
        }
        /// <summary>
        /// If necessary, creates and then returns an instance of the <see cref="AgentClient"/>.
        /// </summary>
        /// <param name="remoteAddress">The remote address where the Agent is running.</param>
        /// <param name="token">The development token used to authenticate with the Agent.</param>
        /// <param name="capabilities">Requested driver options for the browser session.</param>
        /// <param name="reportSettings">Contains the project and job name to report to TestProject.</param>
        /// <param name="disableReports">Set to true to disable all reporting to TestProject, false otherwise.</param>
        /// <param name="compatibleVersion">Minimum Agent version that supports the requested feature. Can be used to check Agent compatibility.</param>
        /// <returns>A instance of the <see cref="AgentClient"/>.</returns>
        public static AgentClient GetInstance(Uri remoteAddress, string token, DriverOptions capabilities, ReportSettings reportSettings, bool disableReports, Version compatibleVersion = null)
        {
            lock (typeof(AgentClient))
            {
                if (IsInitialized())
                {
                    string jobName     = string.Empty;
                    string projectName = string.Empty;
                    if (reportSettings.JobName == null && reportSettings.ProjectName != null)
                    {
                        jobName = StackTraceHelper.Instance.GetInferredJobName();
                    }
                    else if (reportSettings.ProjectName == null && reportSettings.JobName != null)
                    {
                        projectName = StackTraceHelper.Instance.GetInferredProjectName();
                    }
                    else if (reportSettings.ProjectName == null && reportSettings.JobName == null)
                    {
                        projectName = StackTraceHelper.Instance.GetInferredProjectName();
                        jobName     = StackTraceHelper.Instance.GetInferredJobName();
                    }
                    else
                    {
                        jobName     = reportSettings.JobName;
                        projectName = reportSettings.ProjectName;
                    }

                    ReportSettings newSettings = new ReportSettings(projectName, jobName);

                    bool sameReportSettings = instance.reportSettings != null && instance.reportSettings.Equals(newSettings);
                    if (!sameReportSettings || !CanReuseSession())
                    {
                        // Close the dev socket as this is not the same session as previous test
                        SocketManager.GetInstance().CloseSocket();
                    }

                    // Stop the current AgentClient instance and submit the test reports.
                    instance.Stop();
                }

                // Create a new AgentClient instance
                instance = new AgentClient(remoteAddress, token, capabilities, reportSettings, disableReports);
            }

            // Return new instance.
            return(instance);
        }