public async Task CancelAsyncHard() { if (IsMultiplexing) { return; // Multiplexing, cancellation } await using var postmasterMock = PgPostmasterMock.Start(ConnectionString); using var _ = CreateTempPool(postmasterMock.ConnectionString, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); await postmasterMock.WaitForServerConnection(); var processId = conn.ProcessID; var cancellationSource = new CancellationTokenSource(); using var cmd = new NpgsqlCommand("SELECT 1", conn); var t = cmd.ExecuteScalarAsync(cancellationSource.Token); cancellationSource.Cancel(); var exception = Assert.ThrowsAsync <OperationCanceledException>(async() => await t); Assert.That(exception.InnerException, Is.TypeOf <TimeoutException>()); Assert.That(exception.CancellationToken, Is.EqualTo(cancellationSource.Token)); Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken)); Assert.That((await postmasterMock.WaitForCancellationRequest()).ProcessId, Is.EqualTo(processId)); }
public async Task SavepointPrepends() { await using var postmasterMock = PgPostmasterMock.Start(ConnectionString); using var _ = CreateTempPool(postmasterMock.ConnectionString, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); var pgMock = await postmasterMock.WaitForServerConnection(); using var tx = conn.BeginTransaction(); var saveTask = tx.SaveAsync("foo"); Assert.That(saveTask.Status, Is.EqualTo(TaskStatus.RanToCompletion)); // If we're here, SaveAsync above didn't wait for any response, which is the right behavior await pgMock .WriteCommandComplete() .WriteReadyForQuery() // BEGIN response .WriteCommandComplete() .WriteReadyForQuery() // SAVEPOINT response .WriteScalarResponseAndFlush(1); await conn.ExecuteScalarAsync("SELECT 1"); await pgMock.ExpectSimpleQuery("BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED"); await pgMock.ExpectSimpleQuery("SAVEPOINT foo"); await pgMock.ExpectExtendedQuery(); }
public async Task TimeoutAsyncHard() { if (IsMultiplexing) { return; // Multiplexing, Timeout } var builder = new NpgsqlConnectionStringBuilder(ConnectionString) { CommandTimeout = 1 }; await using var postmasterMock = PgPostmasterMock.Start(builder.ConnectionString); using var _ = CreateTempPool(postmasterMock.ConnectionString, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); await postmasterMock.WaitForServerConnection(); var processId = conn.ProcessID; Assert.That(async() => await conn.ExecuteScalarAsync("SELECT 1"), Throws.Exception .TypeOf <NpgsqlException>() .With.InnerException.TypeOf <TimeoutException>()); Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken)); Assert.That((await postmasterMock.WaitForCancellationRequest()).ProcessId, Is.EqualTo(processId)); }
public async Task CancelAsyncHard() { if (IsMultiplexing) { return; // Multiplexing, cancellation } await using var postmasterMock = new PgPostmasterMock(ConnectionString); using var _ = CreateTempPool(postmasterMock.ConnectionString, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); var processId = conn.ProcessID; var cancellationSource = new CancellationTokenSource(); using var cmd = new NpgsqlCommand("SELECT 1", conn); var t = cmd.ExecuteScalarAsync(cancellationSource.Token); cancellationSource.Cancel(); Assert.That(async() => await t, Throws.Exception .TypeOf <OperationCanceledException>() .With.InnerException.Null); Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken)); Assert.That(postmasterMock.GetPendingCancellationRequest().ProcessId, Is.EqualTo(processId)); }
public async Task Bug3466([Values(false, true)] bool isBroken) { if (IsMultiplexing) { return; // Multiplexing, cancellation } var csb = new NpgsqlConnectionStringBuilder(ConnectionString) { Pooling = false, }; await using var postmasterMock = PgPostmasterMock.Start(csb.ToString(), completeCancellationImmediately: false); using var _ = CreateTempPool(postmasterMock.ConnectionString, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); var serverMock = await postmasterMock.WaitForServerConnection(); var processId = conn.ProcessID; using var cancellationSource = new CancellationTokenSource(); using var cmd = new NpgsqlCommand("SELECT 1", conn) { CommandTimeout = 3 }; var t = Task.Run(() => cmd.ExecuteScalar()); // We have to be sure the command's state is InProgress, otherwise the cancellation request will never be sent cmd.WaitUntilCommandIsInProgress(); // Perform cancellation, which will block on the server side var cancelTask = Task.Run(() => cmd.Cancel()); // Note what we have to wait for the cancellation request, otherwise the connection might be closed concurrently // and the cancellation request is never send var cancellationRequest = await postmasterMock.WaitForCancellationRequest(); if (isBroken) { Assert.ThrowsAsync <OperationCanceledException>(async() => await t); Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken)); } else { await serverMock .WriteParseComplete() .WriteBindComplete() .WriteRowDescription(new FieldDescription(PostgresTypeOIDs.Int4)) .WriteDataRow(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(1))) .WriteCommandComplete() .WriteReadyForQuery() .FlushAsync(); Assert.DoesNotThrowAsync(async() => await t); Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open)); await conn.CloseAsync(); } // Release the cancellation at the server side, and make sure it completes without an exception cancellationRequest.Complete(); Assert.DoesNotThrowAsync(async() => await cancelTask); }
public async Task Connect_to_correct_host_with_available_idle( string targetSessionAttributes, MockState[] servers, int expectedServer) { var postmasters = servers.Select(s => PgPostmasterMock.Start(state: s)).ToArray(); await using var __ = new DisposableWrapper(postmasters); // First, open and close a connection with the TargetSessionAttributes matching the first server. // This ensures wew have an idle connection in the pool. var connectionStringBuilder = new NpgsqlConnectionStringBuilder { Host = MultipleHosts(postmasters), TargetSessionAttributes = servers[0] switch { Primary => "read-write", PrimaryReadOnly => "read-only", Standby => "standby", _ => throw new ArgumentOutOfRangeException() },
public async Task Bug3509() { if (IsMultiplexing) { return; } var csb = new NpgsqlConnectionStringBuilder(ConnectionString) { KeepAlive = 1, }; await using var postmasterMock = PgPostmasterMock.Start(csb.ToString()); using var _ = CreateTempPool(postmasterMock.ConnectionString, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); var serverMock = await postmasterMock.WaitForServerConnection(); // Wait for a keepalive to arrive at the server, reply with an error await serverMock.WaitForData(); var queryTask = Task.Run(async() => await conn.ExecuteNonQueryAsync("SELECT 1")); // TODO: kind of flaky - think of the way to rewrite // giving a queryTask some time to get stuck on a lock await Task.Delay(100); await serverMock .WriteErrorResponse("42") .WriteReadyForQuery() .FlushAsync(); await serverMock .WriteScalarResponseAndFlush(1); var ex = Assert.ThrowsAsync <NpgsqlException>(async() => await queryTask) !; Assert.That(ex.InnerException, Is.TypeOf <NpgsqlException>() .With.InnerException.TypeOf <PostgresException>()); }
public async Task Connect_to_correct_host(string targetSessionAttributes, MockState[] servers, int expectedServer) { var postmasters = servers.Select(s => PgPostmasterMock.Start(state: s)).ToArray(); await using var __ = new DisposableWrapper(postmasters); var connectionStringBuilder = new NpgsqlConnectionStringBuilder { Host = MultipleHosts(postmasters), TargetSessionAttributes = targetSessionAttributes, ServerCompatibilityMode = ServerCompatibilityMode.NoTypeLoading, }; using var pool = CreateTempPool(connectionStringBuilder, out var connectionString); await using var conn = await OpenConnectionAsync(connectionString); Assert.That(conn.Port, Is.EqualTo(postmasters[expectedServer].Port)); for (var i = 0; i <= expectedServer; i++) { _ = await postmasters[i].WaitForServerConnection(); } }