コード例 #1
0
        public async Task CorrelationOverflowGuardWorks()
        {
            var correlationId = -1;

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, new ConnectionConfiguration(requestTimeout: TimeSpan.FromMilliseconds(5)), TestConfig.Log)) {
                    server.OnReceivedAsync = data => {
                        var context = KafkaDecoder.DecodeHeader(data.Skip(Request.IntegerByteSize));
                        correlationId = context.CorrelationId;
                        return(Task.FromResult(0));
                    };

                    try {
                        Connection.OverflowGuard = 10;
                        await AssertAsync.Throws <TimeoutException>(() => conn.SendAsync(new MetadataRequest(), CancellationToken.None));

                        var initialCorrelation = correlationId;
                        await AssertAsync.Throws <TimeoutException>(() => Task.WhenAll(Enumerable.Range(initialCorrelation, Connection.OverflowGuard - 1).Select(i => conn.SendAsync(new MetadataRequest(), CancellationToken.None))));

                        await AssertAsync.ThatEventually(() => correlationId > 1, () => $"correlation {correlationId}");

                        var currentCorrelation = correlationId;
                        await AssertAsync.Throws <TimeoutException>(() => Task.WhenAll(Enumerable.Range(0, Connection.OverflowGuard / 2).Select(i => conn.SendAsync(new MetadataRequest(), CancellationToken.None))));

                        await AssertAsync.ThatEventually(() => correlationId < currentCorrelation, () => $"correlation {correlationId}");
                    }
                    finally {
                        Connection.OverflowGuard = int.MaxValue >> 1;
                    }
                }
        }
コード例 #2
0
        public async Task ShouldDisposeEvenWhileAwaitingReadAndThrowException()
        {
            int readSize = 0;
            var config   = new ConnectionConfiguration(onReading: (e, size) => readSize = size);
            var endpoint = TestConfig.ServerEndpoint();

            using (CreateServer(endpoint.Ip.Port, TestConfig.Log)) {
                var transport = CreateTransport(endpoint, config, TestConfig.Log);
                try {
                    await transport.ConnectAsync(CancellationToken.None);

                    var buffer     = new byte[4];
                    var taskResult = transport.ReadBytesAsync(new ArraySegment <byte>(buffer), CancellationToken.None);

                    await AssertAsync.ThatEventually(() => readSize > 0, () => $"readSize {readSize}");

                    using (transport) { }
                    transport = null;

                    await taskResult.CancelAfter();

                    Assert.Fail("Expected ObjectDisposedException to be thrown");
                } catch (ObjectDisposedException) {
                    // expected
                } finally {
                    transport?.Dispose();
                }
            }
        }
コード例 #3
0
        public async Task ReadShouldIgnoreMessageWithUnknownCorrelationId()
        {
            const int correlationId = 99;
            var       onRead        = 0;

            var log = new MemoryLog();

            var config   = new ConnectionConfiguration(onRead: (e, buffer, elapsed) => Interlocked.Increment(ref onRead));
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, config, log: log))
                {
                    //send correlation message
                    await server.SendDataAsync(new ArraySegment <byte>(CreateCorrelationMessage(correlationId)));

                    //wait for connection
                    await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                    await AssertAsync.ThatEventually(() => onRead > 0, () => $"read attempts {onRead}");

                    // shortly after receivedData, but still after
                    await AssertAsync.ThatEventually(() => log.LogEvents.Any(e => e.Item1 == LogLevel.Warn && e.Item2.Message == $"Unexpected response (id {correlationId}, 4? bytes) from {endpoint}"), log.ToString);
                }
        }
コード例 #4
0
        public async Task MessagesStillLogWhenSendTimesOut()
        {
            var logger   = new MemoryLog();
            var received = 0;
            var timeout  = TimeSpan.FromMilliseconds(100);

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, new ConnectionConfiguration(requestTimeout: timeout, onRead: (e, read, elapsed) => Interlocked.Increment(ref received)), logger))
                {
                    await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                    server.OnReceivedAsync = async data => {
                        var context = KafkaDecoder.DecodeHeader(data.Skip(Request.IntegerByteSize));
                        await Task.Delay(timeout);

                        await server.SendDataAsync(KafkaDecoder.EncodeResponseBytes(context, new MetadataResponse()));
                    };

                    await AssertAsync.Throws <TimeoutException>(() => conn.SendAsync(new MetadataRequest(), CancellationToken.None));

                    await AssertAsync.ThatEventually(() => received > 0, () => $"received {received}");

                    await AssertAsync.ThatEventually(() => logger.LogEvents.Any(e => e.Item1 == LogLevel.Debug && e.Item2.Message.StartsWith("Timed out -----> (timed out or otherwise errored in client)")), () => logger.ToString(LogLevel.Debug));
                }
        }
コード例 #5
0
        public async Task ReadShouldThrowServerDisconnectedExceptionWhenDisconnected()
        {
            var disconnectedCount = 0;
            var endpoint          = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log)) {
                server.OnDisconnected = () => Interlocked.Increment(ref disconnectedCount);
                using (var transport = CreateTransport(endpoint, TestConfig.Options.ConnectionConfiguration, TestConfig.Log)) {
                    await transport.ConnectAsync(CancellationToken.None);

                    var buffer     = new byte[48];
                    var taskResult = transport.ReadBytesAsync(new ArraySegment <byte>(buffer, 0, 4), CancellationToken.None);

                    //wait till connected
                    await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                    server.DropConnection();

                    await AssertAsync.ThatEventually(() => disconnectedCount > 0, () => $"disconnected {disconnectedCount}");

                    await Task.WhenAny(taskResult, Task.Delay(1000)).ConfigureAwait(false);

                    Assert.That(taskResult.IsFaulted, Is.True);
                    Assert.That(taskResult.Exception.InnerException, Is.TypeOf <ConnectionException>());
                }
            }
        }
コード例 #6
0
        public async Task WriteAsyncShouldSendData()
        {
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log))
                using (var transport = CreateTransport(endpoint, TestConfig.Options.ConnectionConfiguration, TestConfig.Log))
                {
                    const int testData = 99;
                    var       bytes    = new byte[4];
                    int       read     = 0;

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
                    server.OnReceivedAsync = async data =>
                    {
                        var offset = Interlocked.Add(ref read, data.Count) - data.Count;
                        for (var i = 0; i < data.Count; i++)
                        {
                            bytes[offset + i] = data.Array[data.Offset + i];
                        }
                    };
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

                    await transport.ConnectAsync(CancellationToken.None);

                    await transport.WriteBytesAsync(new ArraySegment <byte>(testData.ToBytes()), CancellationToken.None);

                    await AssertAsync.ThatEventually(() => read == 4 && bytes.ToInt32() == testData, () => $"read {read}");
                }
        }
コード例 #7
0
        //someTime failed
        public async Task ProducerShouldBlockWhenFullBufferReached()
        {
            int count = 0;
            //with max buffer set below the batch size, this should cause the producer to block until batch delay time.
            var scenario = new RoutingScenario();

            scenario.Connection1.Add(ApiKey.Produce, async _ => {
                await Task.Delay(200);
                return(new ProduceResponse());
            });
            using (var producer = new Producer(scenario.CreateRouter(), new ProducerConfiguration(batchSize: 10, batchMaxDelay: TimeSpan.FromMilliseconds(500))))
            {
                var senderTask = Task.Factory.StartNew(async() => {
                    for (int i = 0; i < 3; i++)
                    {
                        await producer.SendAsync(new Message(i.ToString()), RoutingScenario.TestTopic, CancellationToken.None);
                        TestConfig.Log.Info(() => LogEvent.Create($"Buffered {producer.BufferedMessageCount}, In Flight: {producer.InFlightMessageCount}"));
                        Interlocked.Increment(ref count);
                    }
                });

                await AssertAsync.ThatEventually(() => count > 0 && producer.BufferedMessageCount == 1, () => $"buffered {producer.BufferedMessageCount}, count {count}");

                TestConfig.Log.Info(() => LogEvent.Create("Waiting for the rest..."));
                await Task.WhenAny(senderTask, Task.Delay(5000));

                Assert.That(senderTask.IsCompleted);
                Assert.That(producer.BufferedMessageCount, Is.EqualTo(1), "One message should be left in the buffer.");
            }
        }
コード例 #8
0
        public async Task ProducerShouldReportCorrectNumberOfAsyncRequests()
        {
            var semaphore = new SemaphoreSlim(0);
            var scenario  = new RoutingScenario();

            //block the second call returning from send message async
            scenario.Connection1.Add(ApiKey.Produce, async _ =>
            {
                await semaphore.WaitAsync();
                return(new ProduceResponse());
            });

            var router = scenario.CreateRouter();

            using (var producer = new Producer(router, new ProducerConfiguration(requestParallelization: 1, batchSize: 1)))
            {
                var messages = new[] { new Message("1") };

                Assert.That(producer.ActiveSenders, Is.EqualTo(0));

                var sendTask = producer.SendAsync(messages, RoutingScenario.TestTopic, CancellationToken.None);

                await AssertAsync.ThatEventually(() => producer.ActiveSenders >= 1, () => $"senders {producer.ActiveSenders}");

                semaphore.Release();
                await Task.WhenAny(sendTask, Task.Delay(2500));

                Assert.That(sendTask.IsCompleted, Is.True, "Send task should be marked as completed.");
                Assert.That(producer.ActiveSenders, Is.EqualTo(0), "Async should now show zero count.");
            }
        }
コード例 #9
0
        public async Task WriteShouldCancelWhileSendingData()
        {
            var clientWriteAttempts = 0;
            var config   = new ConnectionConfiguration(onWritingBytes: (e, payload) => Interlocked.Increment(ref clientWriteAttempts));
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log)) {
                using (var transport = CreateTransport(endpoint, config, TestConfig.Log)) {
                    using (var token = new CancellationTokenSource())
                    {
                        await transport.ConnectAsync(token.Token);

                        var write = transport.WriteBytesAsync(new ArraySegment <byte>(1.ToBytes()), token.Token);

                        await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                        await AssertAsync.ThatEventually(() => clientWriteAttempts == 1, () => $"attempts {clientWriteAttempts}");

                        //create a buffer write that will take a long time
                        var data = Enumerable.Range(0, 1000000).Select(b => (byte)b).ToArray();
                        token.Cancel();
                        var taskResult = transport.WriteBytesAsync(new ArraySegment <byte>(data), token.Token, 6);
                        await Task.WhenAny(taskResult, Task.Delay(TimeSpan.FromSeconds(2))).ConfigureAwait(false);

                        Assert.That(taskResult.IsCanceled || !taskResult.IsFaulted, Is.True, "Task should have cancelled.");
                    }
                }
            }
        }
コード例 #10
0
        public async Task ShouldStartReadPollingOnConstruction()
        {
            var log      = new MemoryLog();
            var endpoint = TestConfig.ServerEndpoint();

            using (new Connection(endpoint, log: log)) {
                await AssertAsync.ThatEventually(() => log.LogEvents.Any(e => e.Item1 == LogLevel.Info && e.Item2.Message.StartsWith("Connecting to")), log.ToString);
            }
        }
コード例 #11
0
        public async Task AsynchronousWriteAndReadShouldBeConsistent()
        {
            const int requests     = 10;
            var       expected     = requests.Repeat(i => i).ToList();
            var       readOnClient = new ConcurrentBag <int>();

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log)) {
                using (var transport = CreateTransport(endpoint, TestConfig.Options.ConnectionConfiguration, TestConfig.Log)) {
                    var bytes             = new byte[4 * requests];
                    int bytesReadOnServer = 0;
                    server.OnReceivedAsync = data => {
                        var offset = Interlocked.Add(ref bytesReadOnServer, data.Count) - data.Count;
                        for (var i = 0; i < data.Count; i++)
                        {
                            bytes[offset + i] = data.Array[data.Offset + i];
                        }
                        return(Task.FromResult(0));
                    };
                    await transport.ConnectAsync(CancellationToken.None);

                    var clientWriteTasks = expected.Select(i => transport.WriteBytesAsync(new ArraySegment <byte>(i.ToBytes()), CancellationToken.None));
                    var clientReadTasks  = expected.Select(
                        i => {
                        var b = new byte[4];
                        return(transport.ReadBytesAsync(new ArraySegment <byte>(b), CancellationToken.None)
                               .ContinueWith(t => readOnClient.Add(b.ToInt32())));
                    });
                    var serverWriteTasks = expected.Select(i => server.SendDataAsync(new ArraySegment <byte>(i.ToBytes())));

                    await Task.WhenAll(clientWriteTasks.Union(clientReadTasks).Union(serverWriteTasks));

                    await AssertAsync.ThatEventually(() => bytesReadOnServer == bytes.Length, () => $"length {bytes.Length}, read {bytesReadOnServer}");

                    var readOnServer = new List <int>();
                    foreach (var value in bytes.Batch(4).Select(x => x.ToArray().ToInt32()))
                    {
                        readOnServer.Add(value);
                    }
                    Assert.That(readOnServer.Count, Is.EqualTo(requests), "not all writes propagated to the server in time");
                    await AssertAsync.ThatEventually(() => readOnClient.Count == requests, () => $"read {readOnClient.Count}, requests {requests}");

                    var w = readOnServer.OrderBy(x => x);
                    var r = readOnClient.OrderBy(x => x);

                    for (var i = 0; i < requests; i++)
                    {
                        Assert.That(w.ElementAt(i), Is.EqualTo(expected[i]));
                    }
                    for (var i = 0; i < requests; i++)
                    {
                        Assert.That(r.ElementAt(i), Is.EqualTo(expected[i]));
                    }
                }
            }
        }
コード例 #12
0
        public async Task ShouldAttemptMultipleTimesWhenConnectionFails()
        {
            var count  = 0;
            var config = new ConnectionConfiguration(onConnecting: (e, a, _) => Interlocked.Increment(ref count));

            using (var transport = CreateTransport(TestConfig.ServerEndpoint(), config, TestConfig.Log)) {
                var task = transport.ConnectAsync(CancellationToken.None);
                await AssertAsync.ThatEventually(() => count > 1, TimeSpan.FromSeconds(10), () => $"count {count}");
            }
        }
コード例 #13
0
        public async Task ShouldStartDedicatedThreadOnConstruction()
        {
            var count    = 0;
            var config   = new ConnectionConfiguration(onConnecting: (e, a, _) => Interlocked.Increment(ref count));
            var endpoint = TestConfig.ServerEndpoint();

            using (new Connection(endpoint, config, log: TestConfig.Log)) {
                await AssertAsync.ThatEventually(() => count > 0, () => $"count {count}");
            }
        }
コード例 #14
0
        public async Task ShouldAttemptMultipleTimesWhenConnectionFails()
        {
            var count  = 0;
            var config = new ConnectionConfiguration(onConnecting: (e, a, _) => Interlocked.Increment(ref count));

            using (var conn = new Connection(TestConfig.ServerEndpoint(), config, TestConfig.Log))
            {
                var task = conn.SendAsync(new FetchRequest(), CancellationToken.None); //will force a connection
                await AssertAsync.ThatEventually(() => count > 1, TimeSpan.FromSeconds(10), () => $"count {count}");
            }
        }
コード例 #15
0
        public async Task ShouldFinishPartiallyReadMessage()
        {
            var log         = new MemoryLog();
            var bytesRead   = 0;
            var firstLength = 99;

            var config = new ConnectionConfiguration(onReadBytes: (e, attempted, actual, elapsed) => {
                if (Interlocked.Add(ref bytesRead, actual) == firstLength)
                {
                    throw new OutOfMemoryException();
                }
            });

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (new Connection(endpoint, config, log))
                {
                    // send size
                    var size = 200;
                    await server.SendDataAsync(new ArraySegment <byte>(size.ToBytes()));

                    var bytes = new byte[size];
                    new Random(42).NextBytes(bytes);
                    var offset        = 0;
                    var correlationId = 200;
                    foreach (var b in correlationId.ToBytes())
                    {
                        bytes[offset++] = b;
                    }

                    // send half of payload
                    await server.SendDataAsync(new ArraySegment <byte>(bytes, 0, firstLength));

                    await AssertAsync.ThatEventually(() => bytesRead >= firstLength, () => $"read {bytesRead}, length {bytes.Length}");

                    Assert.That(log.LogEvents.Count(e => e.Item1 == LogLevel.Warn && e.Item2.Message.StartsWith($"Unexpected response (id {correlationId}, {size}? bytes) from")), Is.EqualTo(1), log.ToString());
                    Assert.That(log.LogEvents.Count(e => e.Item1 == LogLevel.Debug && e.Item2.Message.StartsWith($"Received {size} bytes (id {correlationId})")), Is.EqualTo(0));

                    // send half of payload should be skipped
                    while (!await server.SendDataAsync(new ArraySegment <byte>(bytes, firstLength, size - firstLength)))
                    {
                        // repeat until the connection is all up and working ...
                    }
                    await AssertAsync.ThatEventually(() => bytesRead >= size, () => $"read {bytesRead}, size {size}");

                    await AssertAsync.ThatEventually(() => log.LogEvents.Count(e => e.Item1 == LogLevel.Info && e.Item2.Message.StartsWith($"Received {size} bytes (id {correlationId})")) == 1, log.ToString);
                }
        }
コード例 #16
0
        public async Task TimedOutQueueIsClearedWhenTooBig()
        {
            var logger  = new MemoryLog();
            var timeout = TimeSpan.FromMilliseconds(1);

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, new ConnectionConfiguration(requestTimeout: timeout), logger)) {
                    await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                    await AssertAsync.Throws <TimeoutException>(() => Task.WhenAll(Enumerable.Range(0, 201).Select(i => conn.SendAsync(new MetadataRequest(), CancellationToken.None))));

                    await AssertAsync.ThatEventually(() => logger.LogEvents.Any(e => e.Item1 == LogLevel.Debug && e.Item2.Message.StartsWith("Clearing timed out requests to avoid overflow")), () => logger.ToString(LogLevel.Debug));
                }
        }
コード例 #17
0
        public async Task SendAsyncShouldUseStatictVersionInfo()
        {
            IRequestContext context  = null;
            var             endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, new ConnectionConfiguration(requestTimeout: TimeSpan.FromSeconds(1000), versionSupport: VersionSupport.Kafka10), log: TestConfig.Log))
                {
                    server.OnReceivedAsync = async data => {
                        context = KafkaDecoder.DecodeHeader(data.Skip(Request.IntegerByteSize));
                        await server.SendDataAsync(KafkaDecoder.EncodeResponseBytes(context, new FetchResponse()));
                    };

                    await conn.SendAsync(new FetchRequest(new FetchRequest.Topic("Foo", 0, 0)), CancellationToken.None);

                    await AssertAsync.ThatEventually(() => context != null && context.ApiVersion.GetValueOrDefault() == 2, () => $"version {context?.ApiVersion}");
                }
        }
コード例 #18
0
        public async Task ShouldDisposeEvenWhilePollingToReconnect()
        {
            var connectionAttempt = -1;
            var config            = new ConnectionConfiguration(Retry.Until(TimeSpan.FromSeconds(10)), onConnecting: (e, a, _) => connectionAttempt = a);
            var endpoint          = TestConfig.ServerEndpoint();

            using (var transport = CreateTransport(endpoint, config, TestConfig.Log)) {
                var taskResult = transport.ConnectAsync(CancellationToken.None);

                await AssertAsync.ThatEventually(() => connectionAttempt >= 0, () => $"attempt {connectionAttempt}");

                transport.Dispose();

                using (var cancellation = new TimedCancellation(CancellationToken.None, TimeSpan.FromSeconds(3))) {
                    await AssertAsync.Throws <ObjectDisposedException>(() => taskResult.ThrowIfCancellationRequested(cancellation.Token));
                }
            }
        }
コード例 #19
0
 public async Task ReadShouldReconnectEvenAfterCancelledRead()
 {
     using (var token = new CancellationTokenSource()) {
         var connectionAttempt = 0;
         var config            = new ConnectionConfiguration(
             onConnecting: (e, attempt, elapsed) => {
             if (Interlocked.Increment(ref connectionAttempt) > 1)
             {
                 token.Cancel();
             }
         });
         var endpoint = TestConfig.ServerEndpoint();
         using (var conn = new Connection(endpoint, config, TestConfig.Log)) {
             var taskResult = conn.SendAsync(new FetchRequest(), token.Token);
             await AssertAsync.ThatEventually(() => connectionAttempt > 1, () => $"attempt {connectionAttempt}");
         }
     }
 }
コード例 #20
0
        public async Task SendAsyncWithDynamicVersionInfoMakesVersionCallFirst()
        {
            var firstCorrelation = -1;
            var correlationId    = 0;
            var sentVersion      = (short)-1;

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, new ConnectionConfiguration(requestTimeout: TimeSpan.FromSeconds(3), versionSupport: VersionSupport.Kafka8.Dynamic()), log: TestConfig.Log))
                {
                    var apiVersion = (short)3;
                    server.OnReceivedAsync = async data => {
                        var context = KafkaDecoder.DecodeHeader(data.Skip(Request.IntegerByteSize));
                        if (firstCorrelation < 0)
                        {
                            firstCorrelation = context.CorrelationId;
                        }
                        correlationId = context.CorrelationId;
                        switch (correlationId - firstCorrelation)
                        {
                        case 0:
                            await server.SendDataAsync(KafkaDecoder.EncodeResponseBytes(context, new ApiVersionsResponse(ErrorCode.NONE, new[] { new ApiVersionsResponse.VersionSupport(ApiKey.Fetch, apiVersion, apiVersion) })));

                            break;

                        case 1:
                            sentVersion = context.ApiVersion.GetValueOrDefault();
                            await server.SendDataAsync(KafkaDecoder.EncodeResponseBytes(context, new FetchResponse()));

                            break;

                        default:
                            return;
                        }
                    };

                    await conn.SendAsync(new FetchRequest(new FetchRequest.Topic("Foo", 0, 0)), CancellationToken.None);

                    await AssertAsync.ThatEventually(() => correlationId - firstCorrelation >= 1, () => $"first {firstCorrelation}, current {correlationId}");

                    Assert.That(sentVersion, Is.EqualTo(apiVersion));
                }
        }
コード例 #21
0
        public async Task ShouldLogDisconnectAndRecover()
        {
            var log = new MemoryLog();
            var clientDisconnected = 0;
            var clientConnected    = 0;
            var serverConnected    = 0;

            var config = new ConnectionConfiguration(
                onDisconnected: (e, exception) => {
                Interlocked.Increment(ref clientDisconnected);
            },
                onConnected: (e, attempt, elapsed) => {
                Interlocked.Increment(ref clientConnected);
            });

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log)
            {
                OnConnected = () => Interlocked.Increment(ref serverConnected)
            })
                using (new Connection(endpoint, config, log: log))
                {
                    for (var connectionAttempt = 1; connectionAttempt <= 4; connectionAttempt++)
                    {
                        var currentAttempt = connectionAttempt;
                        await AssertAsync.ThatEventually(() => serverConnected == currentAttempt, () => $"server {serverConnected}, attempt {currentAttempt}");

                        await server.SendDataAsync(new ArraySegment <byte>(CreateCorrelationMessage(connectionAttempt)));

                        TestConfig.Log.Write(LogLevel.Info, () => LogEvent.Create($"Sent CONNECTION attempt {currentAttempt}"));
                        await AssertAsync.ThatEventually(() => clientConnected == currentAttempt, TimeSpan.FromMilliseconds(200), () => $"client {clientConnected}, attempt {currentAttempt}");

                        await AssertAsync.ThatEventually(() => log.LogEvents.Count(e => e.Item1 == LogLevel.Info && e.Item2.Message.StartsWith("Received 4 bytes (id ")) == currentAttempt, () => $"attempt {currentAttempt}\n" + log.ToString(LogLevel.Info));

                        TestConfig.Log.Write(LogLevel.Info, () => LogEvent.Create($"Dropping CONNECTION attempt {currentAttempt}"));
                        server.DropConnection();
                        await AssertAsync.ThatEventually(() => clientDisconnected == currentAttempt, () => $"client {clientDisconnected}, attempt {currentAttempt}");

                        Assert.That(log.LogEvents.Count(e => e.Item1 == LogLevel.Info && e.Item2.Message.StartsWith("Disposing transport to")), Is.AtLeast(currentAttempt));
                    }
                }
        }
コード例 #22
0
        public async Task ReadShouldBlockUntilAllBytesRequestedAreReceived()
        {
            var readCompleted = 0;
            var bytesReceived = 0;
            var config        = new ConnectionConfiguration(
                onReadBytes: (e, attempted, actual, elapsed) => Interlocked.Add(ref bytesReceived, actual),
                onRead: (e, read, elapsed) => Interlocked.Increment(ref readCompleted));
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log)) {
                using (var transport = CreateTransport(endpoint, config, TestConfig.Log)) {
                    await transport.ConnectAsync(CancellationToken.None);

                    var buffer   = new byte[4];
                    var readTask = transport.ReadBytesAsync(new ArraySegment <byte>(buffer), CancellationToken.None);

                    TestConfig.Log.Info(() => LogEvent.Create("Sending the first 3 bytes"));
                    await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                    await server.SendDataAsync(new ArraySegment <byte>(new byte[] { 0, 0, 0 }));

                    // Three bytes should have been received and we are waiting on the last byte.
                    await AssertAsync.ThatEventually(() => bytesReceived >= 3, () => $"bytesReceived {bytesReceived}");

                    Assert.That(readTask.IsCompleted, Is.False, "Task should still be running, blocking.");
                    Assert.That(readCompleted, Is.EqualTo(0), "Should still block even though bytes have been received.");

                    TestConfig.Log.Info(() => LogEvent.Create("Sending the last bytes"));
                    var sendLastByte = await server.SendDataAsync(new ArraySegment <byte>(new byte[] { 0 }));

                    Assert.That(sendLastByte, Is.True, "Last byte should have sent.");

                    // Ensuring task unblocks...
                    await AssertAsync.ThatEventually(() => readTask.IsCompleted);

                    Assert.That(bytesReceived, Is.EqualTo(4), "");
                    Assert.That(readCompleted, Is.EqualTo(1), "Task ContinueWith should have executed.");
                }
            }
        }
コード例 #23
0
        public async Task ProducerShouldAllowFullBatchSizeOfMessagesToQueue()
        {
            var scenario = new RoutingScenario();
            var producer = new Producer(scenario.CreateRouter(), new ProducerConfiguration(batchSize: 1002, batchMaxDelay: TimeSpan.FromSeconds(10000)));

            using (producer)
            {
                var count = 1000;

                var senderTask = Task.Run(() => {
                    for (var i = 0; i < count; i++)
                    {
                        producer.SendAsync(new Message(i.ToString()), RoutingScenario.TestTopic, CancellationToken.None);
                    }
                });
                await senderTask;
                TestConfig.Log.Info(() => LogEvent.Create("Finished test send task"));

                Assert.That(senderTask.IsCompleted);
                await AssertAsync.ThatEventually(() => producer.InFlightMessageCount + producer.BufferedMessageCount == count, () => $"in flight {producer.InFlightMessageCount}, buffered {producer.BufferedMessageCount}, total {count}");
            }
        }
コード例 #24
0
        public async Task ShouldReconnectAfterLosingConnectionAndBeAbleToStartNewRead()
        {
            var log      = TestConfig.Log;
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log)) {
                var serverDisconnects = 0;
                var serverConnects    = 0;
                var clientDisconnects = 0;
                var clientReads       = 0;
                var clientBytesRead   = 0;

                server.OnConnected    = () => Interlocked.Increment(ref serverConnects);
                server.OnDisconnected = () => Interlocked.Increment(ref serverDisconnects);
                var config = new ConnectionConfiguration(
                    onDisconnected: (e, exception) => Interlocked.Increment(ref clientDisconnects),
                    onReading: (e, available) => Interlocked.Increment(ref clientReads),
                    onRead: (e, read, elapsed) => Interlocked.Add(ref clientBytesRead, read));
                using (var conn = new Connection(endpoint, config, log)) {
                    await AssertAsync.ThatEventually(() => serverConnects > 0, () => $"connects {serverConnects}");

                    await AssertAsync.ThatEventually(() => clientReads > 0, TimeSpan.FromSeconds(1), () => $"reads {clientReads}");

                    server.DropConnection();

                    await AssertAsync.ThatEventually(() => clientDisconnects > 0, TimeSpan.FromSeconds(10), () => $"disconnects {clientDisconnects}");

                    Assert.That(clientBytesRead, Is.EqualTo(0), "client should not have received any bytes.");

                    await AssertAsync.ThatEventually(() => serverConnects == 2, TimeSpan.FromSeconds(6), () => $"connects {serverConnects}");

                    await server.SendDataAsync(new ArraySegment <byte>(8.ToBytes()));

                    await server.SendDataAsync(new ArraySegment <byte>(99.ToBytes()));

                    await AssertAsync.ThatEventually(() => clientBytesRead == 8, TimeSpan.FromSeconds(1), () => $"bytes read {clientBytesRead}");
                }
            }
        }
コード例 #25
0
        public async Task SendAsyncShouldBlockWhenMaximumAsyncQueueReached()
        {
            TestConfig.Log.Info(() => LogEvent.Create("Start SendAsyncShouldBlockWhenMaximumAsyncQueueReached"));
            int count     = 0;
            var semaphore = new SemaphoreSlim(0);
            var scenario  = new RoutingScenario();

            //block the second call returning from send message async
            scenario.Connection1.Add(ApiKey.Produce,
                                     async _ => {
                await semaphore.WaitAsync();
                return(new ProduceResponse());
            });

            var router = scenario.CreateRouter();

            using (var producer = new Producer(router, new ProducerConfiguration(requestParallelization: 1, batchSize: 1)))
            {
                var messages = new[] { new Message("1") };

                var task = Task.Run(async() =>
                {
                    var t = producer.SendAsync(messages, RoutingScenario.TestTopic, CancellationToken.None);
                    Interlocked.Increment(ref count);
                    await t;

                    t = producer.SendAsync(messages, RoutingScenario.TestTopic, CancellationToken.None);

                    Interlocked.Increment(ref count);
                    await t;
                });

                await AssertAsync.ThatEventually(() => producer.ActiveSenders == 1 && count > 0, () => $"senders {producer.ActiveSenders}, count {count}");

                semaphore.Release();
                // The second SendMessagesAsync should continue after semaphore is released.
                await AssertAsync.ThatEventually(() => count > 1, () => $"count {count}");
            }
        }
コード例 #26
0
        public async Task WriteShouldHandleLargeVolumeSendAsynchronously([Values(1000, 5000)] int requests)
        {
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log)) {
                using (var transport = CreateTransport(endpoint, TestConfig.Options.ConnectionConfiguration, TestConfig.Log)) {
                    var bytes             = new byte[4 * requests];
                    int bytesReadOnServer = 0;

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
                    server.OnReceivedAsync = async data =>
                    {
                        var offset = Interlocked.Add(ref bytesReadOnServer, data.Count) - data.Count;
                        for (var i = 0; i < data.Count; i++)
                        {
                            bytes[offset + i] = data.Array[data.Offset + i];
                        }
                    };
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

                    await transport.ConnectAsync(CancellationToken.None);

                    var clientWriteTasks = Enumerable.Range(1, requests).Select(i => transport.WriteBytesAsync(new ArraySegment <byte>(i.ToBytes()), CancellationToken.None));

                    await Task.WhenAll(clientWriteTasks);

                    await AssertAsync.ThatEventually(() => bytesReadOnServer == bytes.Length, () => $"bytes read {bytesReadOnServer}, total {bytes.Length}");

                    var readOnServer = new List <int>();
                    foreach (var value in bytes.Batch(4).Select(x => x.ToArray().ToInt32()))
                    {
                        readOnServer.Add(value);
                    }
                    Assert.That(readOnServer.Count, Is.EqualTo(requests), "not all writes propagated to the server in time");
                    Assert.That(readOnServer.OrderBy(x => x), Is.EqualTo(Enumerable.Range(1, requests)));
                }
            }
        }
コード例 #27
0
        public async Task ShouldNotFinishPartiallyReadMessage()
        {
            var log       = new MemoryLog();
            var bytesRead = 0;

            var config = new ConnectionConfiguration(onReadBytes: (e, attempted, actual, elapsed) => Interlocked.Add(ref bytesRead, actual));

            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (new Connection(endpoint, config, log))
                {
                    // send size
                    var size = 200;
                    await server.SendDataAsync(new ArraySegment <byte>(size.ToBytes()));

                    var bytes = new byte[99];
                    new Random(42).NextBytes(bytes);
                    var offset        = 0;
                    var correlationId = 200;
                    foreach (var b in correlationId.ToBytes())
                    {
                        bytes[offset++] = b;
                    }

                    // send half of payload
                    await server.SendDataAsync(new ArraySegment <byte>(bytes, 0, 99));

                    await AssertAsync.ThatEventually(() => bytesRead >= bytes.Length, () => $"read {bytesRead}, length {bytes.Length}");

                    Assert.That(log.LogEvents.Count(e => e.Item1 == LogLevel.Warn && e.Item2.Message.StartsWith($"Unexpected response (id {correlationId}, {size}? bytes) from")), Is.EqualTo(1), log.ToString());
                    Assert.That(log.LogEvents.Count(e => e.Item1 == LogLevel.Debug && e.Item2.Message.StartsWith($"Received {size} bytes (id {correlationId})")), Is.EqualTo(0));

                    server.DropConnection();

                    await AssertAsync.ThatEventually(() => log.LogEvents.Count(e => e.Item1 == LogLevel.Warn && e.Item2.Message.StartsWith("Socket has been re-established, so recovery of the remaining of the current message is uncertain at best")) == 1, log.ToString);
                }
        }
コード例 #28
0
        public async Task WriteAsyncShouldAllowMoreThanOneWrite()
        {
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = CreateServer(endpoint.Ip.Port, TestConfig.Log))
                using (var transport = CreateTransport(endpoint, TestConfig.Options.ConnectionConfiguration, TestConfig.Log))
                {
                    const int testData = 99;
                    var       results  = new List <byte>();

#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
                    server.OnReceivedAsync = async data => results.AddRange(data.Array.Skip(data.Offset).Take(data.Count));
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously

                    await transport.ConnectAsync(CancellationToken.None);

                    await Task.WhenAll(
                        transport.WriteBytesAsync(new ArraySegment <byte>(testData.ToBytes()), CancellationToken.None),
                        transport.WriteBytesAsync(new ArraySegment <byte>(testData.ToBytes()), CancellationToken.None));

                    await AssertAsync.ThatEventually(() => results.Count == 8, () => $"count {results.Count}");
                }
        }
コード例 #29
0
        public async Task SendAsyncShouldTimeoutMultipleMessagesAtATime()
        {
            var endpoint = TestConfig.ServerEndpoint();

            using (var server = new TcpServer(endpoint.Ip.Port, TestConfig.Log))
                using (var conn = new Connection(endpoint, new ConnectionConfiguration(requestTimeout: TimeSpan.FromMilliseconds(100)), log: TestConfig.Log))
                {
                    await Task.WhenAny(server.ClientConnected, Task.Delay(TimeSpan.FromSeconds(3)));

                    var tasks = new[] {
                        conn.SendAsync(new MetadataRequest(), CancellationToken.None),
                        conn.SendAsync(new MetadataRequest(), CancellationToken.None),
                        conn.SendAsync(new MetadataRequest(), CancellationToken.None)
                    };

                    await AssertAsync.ThatEventually(() => tasks.All(t => t.IsFaulted));

                    foreach (var task in tasks)
                    {
                        Assert.That(task.IsFaulted, Is.True, "Task should have faulted.");
                        Assert.That(task.Exception.InnerException, Is.TypeOf <TimeoutException>(), "Task fault has wrong type.");
                    }
                }
        }