Exemplo n.º 1
0
        /// <summary>
        /// Mains entry-point.
        /// </summary>
        /// <param name="args">The command-line arguments. We expect none at the moment.</param>
        public static void Main(string[] args)
        {
            // Just to make sure there isn't anything fuffing around with the number of concurrent requests.
            System.Net.ServicePointManager.DefaultConnectionLimit = int.MaxValue;

            var consoleWriteLine = StringWriterFuns.ConsoleWriter();

            var options = new CommandLineOptions();

            if (!CommandLine.Parser.Default.ParseArgumentsStrict(args, options))
            {
                consoleWriteLine("Something is wrong with command-line arguments.");
                Environment.Exit(-1);
            }

            var replayFileNames  = options.ExpandedReplayFiles();
            var replayFiles      = new ReplayFile[replayFileNames.Length];
            var replayFileErrors = 0;

            for (var i = 0; i < replayFileNames.Length; i++)
            {
                var replayFileName = replayFileNames[i];

                try
                {
                    var content = File.ReadAllText(replayFileName);
                    content = Environment.ExpandEnvironmentVariables(content);
                    var replay = Newtonsoft.Json.JsonConvert.DeserializeObject <ReplayFile>(content);
                    replayFiles[i] = replay;

                    consoleWriteLine("Yay!: {0}", replayFileName);
                    consoleWriteLine("    - {0}", replay.Name);
                    consoleWriteLine("    - {0}", replay.Description);
                    consoleWriteLine("    - {0}", replay.BaseUri);
                    consoleWriteLine("    - {0}", replay.Headers);
                    consoleWriteLine("    - {0} uris", replay.Uris.Length.ToString("G"));
                }
                catch (Exception e)
                {
                    consoleWriteLine("**** ERROR reading replay file: {0}", replayFileName);
                    consoleWriteLine(e.ToString());
                    replayFileErrors++;
                }
            }

            if (replayFileErrors > 0)
            {
                consoleWriteLine("+++++ Could not read all replay files. Exiting.");
                Environment.Exit(-1);
            }

            if (replayFiles.Length == 0)
            {
                consoleWriteLine("+++++ No suitable replay files.");
                Environment.Exit(-1);
            }

            if (options.OutFile != null && File.Exists(options.OutFile))
            {
                File.Delete(options.OutFile);
            }

            StringWriterFuns.WriteLineFun writeReportLine;
            if (options.OutFile != null)
            {
                writeReportLine = StringWriterFuns.AggregateWriter(
                    new[]
                {
                    StringWriterFuns.ConsoleWriter(),
                    StringWriterFuns.FileWriter(options.OutFile)
                });
            }
            else
            {
                writeReportLine = StringWriterFuns.ConsoleWriter();
            }

            // The CSV header with field names.
            const string Header = "Sequence, Iterations, Concurrent Requests, TestStartTimeUtc, TestEndTimeUtc, TestDurationMs, Status Code, Response Size, Response Checksum, Req/Sec, min, perc50, perc75, perc90, perc95, max, description, baseUri, uri";

            writeReportLine(Header);

            // The callback for completed HTTP request. We use it here to
            // write the CSV result into the file. Keep the sequence number
            // so that we can print that out too.
            var sequenceNumber = 0;
            Action <ReplayFilerRunnerResult> callback = (r) =>
            {
                sequenceNumber++;

                var line = string.Format(
                    "{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}",
                    sequenceNumber.ToString("G"),
                    r.Iterations.ToString("G"),
                    r.ConcurrentRequests.ToString("G"),
                    r.TestStartTime.ToUniversalTime().ToString("yyy-mm-dd HH:MM:ss.fff"),
                    r.TestEndTime.ToUniversalTime().ToString("yyy-mm-dd HH:MM:ss.fff"),
                    r.TestDuration.TotalMilliseconds.ToString("F"),
                    r.LastStatusCode.ToString("G"),
                    r.LastResponseBodySize.ToString("G"),
                    r.LastResponseBodyChecksum,
                    r.RequestsPerSec.ToString("F"),
                    r.ResponseTimeMin.TotalMilliseconds.ToString("G"),
                    r.ResponseTimePerc50.TotalMilliseconds.ToString("G"),
                    r.ResponseTimePerc75.TotalMilliseconds.ToString("G"),
                    r.ResponseTimePerc90.TotalMilliseconds.ToString("G"),
                    r.ResponseTimePerc95.TotalMilliseconds.ToString("G"),
                    r.ResponseTimeMax.TotalMilliseconds.ToString("G"),
                    r.Description,
                    r.BaseUri,
                    r.Uri);

                writeReportLine(line);
            };

            foreach (var replayFile in replayFiles)
            {
                var uriRunnerOptions = new UriRunnerOptions(
                    calculateBodySize: options.CalculateBodySize,
                    calculateBodyChecksum: options.CalculateBodyChecksum);

                ReplayFileRunner.RunReplayFileAsync(
                    replayFile: replayFile,
                    callback: callback,
                    uriRunnerOptions: uriRunnerOptions,
                    iterations: options.Iterations,
                    concurrentRequests: options.Concurrency).Wait();
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Asynchronously runs the specified replay file.
        /// </summary>
        /// <param name="replayFile">The replay file.</param>
        /// <param name="callback">The callback to call at the completion of each of the request in the replay file..</param>
        /// <param name="uriRunnerOptions">The options for the uri runner.</param>
        /// <param name="iterations">The iterations.</param>
        /// <param name="concurrentRequests">The number of concurrent requests to execute.</param>
        /// <returns>The list of the results.</returns>
        public static async Task RunReplayFileAsync(
            ReplayFile replayFile,
            Action <ReplayFilerRunnerResult> callback,
            UriRunnerOptions uriRunnerOptions,
            int iterations         = 1,
            int concurrentRequests = 1)
        {
            var consoleWriteLine = StringWriterFuns.ConsoleWriter();

            using (var handler = new HttpClientHandler())
                using (var client = new HttpClient(handler))
                {
                    handler.AllowAutoRedirect      = true;
                    handler.AutomaticDecompression = DecompressionMethods.None;
                    handler.UseProxy = true;

                    // Need to set this to false to make sure the http client does not
                    // mess around with our own cookies.
                    handler.UseCookies = false;

                    client.BaseAddress = new Uri(replayFile.BaseUri);
                    foreach (var header in replayFile.Headers)
                    {
                        if (!client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value))
                        {
                            consoleWriteLine("Failed to add header: {0} = {1}", header.Key, header.Value);
                        }
                    }

                    foreach (var uri in replayFile.Uris)
                    {
                        var sw = new Stopwatch();

                        var numberOfRequests = iterations * concurrentRequests;
                        var allResults       = new List <UriRunnerResult>(capacity: numberOfRequests);
                        var startTimeUtc     = DateTimeOffset.UtcNow;

                        // Exec same URI with the specified concurrency level
                        var uris = Enumerable.Repeat(uri, concurrentRequests).ToArray();
                        for (var i = 0; i < iterations; i++)
                        {
                            sw.Start();
                            var runUrisResults = await UriRunner.RunUrisConcurrentlyAsync(
                                client : client,
                                uris : uris,
                                uriRunnerOptions : uriRunnerOptions);

                            sw.Stop();
                            allResults.AddRange(runUrisResults);
                        }

                        var endTimeUtc     = DateTimeOffset.UtcNow;
                        var requestsPerSec = (double)numberOfRequests / sw.Elapsed.TotalSeconds;
                        var responseTimes  = allResults.Select(r => r.ResponseTime);
                        var percentiles    = new PercentileStats <TimeSpan>(responseTimes);

                        var lastResult = allResults.Last();

                        var reportLine = new ReplayFilerRunnerResult(
                            iterations: iterations,
                            concurrentRequests: concurrentRequests,
                            lastStatusCode: (int)lastResult.StatusCode,
                            lastResponseBodySize: lastResult.BodySize,
                            lastResponseBodyChecksum: lastResult.BodyChecksum,
                            responseTimeStats: percentiles,
                            description: replayFile.Description,
                            baseUri: replayFile.BaseUri,
                            uri: uri,
                            requestsPerSec: requestsPerSec,
                            testStartTime: startTimeUtc,
                            testEndTime: endTimeUtc);

                        if (callback != null)
                        {
                            callback(reportLine);
                        }
                    }
                }
        }