private static SenderInfo CreatePartitionSender(double n, StreamOptions x, string id, PartitionSender sender)
        {
            var si = new SenderInfo()
            {
                PartitionId = id,
            };

            si.Thread = new Thread(() =>
            {
                Console.WriteLine($"Thread started to send to {id}, sending {n} events...");

                var epoch     = DateTime.UtcNow;
                var sessionId = Guid.NewGuid();
                var deviceId  = Guid.NewGuid();

                EventDataBatch batch = null;
                while (n >= 0)
                {
                    if (batch == null)
                    {
                        batch = sender.CreateBatch(new BatchOptions());
                    }

                    var e = GenerateEvent(epoch, si.SendCount, sessionId, deviceId);

                    if (!batch.TryAdd(e))
                    {
                        // flush
                        sender.SendAsync(batch).Wait();

                        batch = null;

                        // and go to continue, because we need to resend the event that failed
                        continue;
                    }

                    // looks like that went through, yay
                    epoch = epoch.AddMilliseconds(x.Interval);

                    Thread.Sleep(x.Pause);
                    n--;
                    si.SendCount++;
                }

                if (batch != null)
                {
                    sender.SendAsync(batch).Wait();
                }

                si.Event.Set();
            });

            si.Thread.Start();

            return(si);
        }
        /// <summary>
        ///   Executes the performance test scenario asynchronously.
        /// </summary>
        ///
        /// <param name="cancellationToken">The token used to signal when cancellation is requested.</param>
        ///
        public async override Task RunAsync(CancellationToken cancellationToken)
        {
            using var batch = s_sender.CreateBatch();

            // Fill the batch with events using the same body.  This will result in a batch of events of equal size.
            // The events will only differ by the id property that is assigned to them.

            foreach (var eventData in EventGenerator.CreateEventsFromBody(Options.Count, s_eventBody))
            {
                if (!batch.TryAdd(eventData))
                {
                    throw new InvalidOperationException("It was not possible to fit the requested number of events in a single batch.");
                }
            }

            await s_sender.SendAsync(batch).ConfigureAwait(false);
        }
        /// <summary>
        ///   Performs the tasks needed to initialize and set up the environment for the test scenario.
        ///   When multiple instances are run in parallel, the setup will take place once, prior to the
        ///   execution of the first test instance.
        /// </summary>
        ///
        public async override Task GlobalSetupAsync()
        {
            await base.GlobalSetupAsync().ConfigureAwait(false);

            s_scope = await EventHubScope.CreateAsync(4).ConfigureAwait(false);

            s_client    = EventHubClient.CreateFromConnectionString(TestUtility.BuildEventHubsConnectionString(s_scope.EventHubName));
            s_eventBody = EventGenerator.CreateRandomBody(Options.Size);

            var partition = (await s_client.GetRuntimeInformationAsync().ConfigureAwait(false)).PartitionIds[0];

            s_sender = s_client.CreatePartitionSender(partition);

            // Publish an empty event to force the connection and link to be established.

            using var batch = s_sender.CreateBatch();

            if (!batch.TryAdd(new EventData(Array.Empty <byte>())))
            {
                throw new InvalidOperationException("The empty event could not be added to the batch during global setup.");
            }

            await s_sender.SendAsync(batch).ConfigureAwait(false);
        }