Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ jobs:
- 8765:8765
env:
YDB_LOCAL_SURVIVE_RESTART: true
YDB_USE_IN_MEMORY_PDISKS: true
options: '--name ydb-local -h localhost'
env:
OS: ubuntu-22.04
Expand All @@ -72,7 +71,7 @@ jobs:
run: |
docker cp ydb-local:/ydb_certs/ca.pem ~/
cd src
dotnet test --filter "(FullyQualifiedName~Ado) | (FullyQualifiedName~Dapper)" -l "console;verbosity=normal"
dotnet test --filter "(FullyQualifiedName~Ado) | (FullyQualifiedName~Dapper)" -f ${{ matrix.dotnet-target-framework }} -l "console;verbosity=normal"
topic-tests:
runs-on: ubuntu-22.04
strategy:
Expand All @@ -94,7 +93,6 @@ jobs:
- 8765:8765
env:
YDB_LOCAL_SURVIVE_RESTART: true
YDB_USE_IN_MEMORY_PDISKS: true
options: '--name ydb-local -h localhost'
env:
OS: ubuntu-22.04
Expand All @@ -112,7 +110,7 @@ jobs:
run: |
docker cp ydb-local:/ydb_certs/ca.pem ~/
cd src
dotnet test --filter "FullyQualifiedName~Topic" -l "console;verbosity=normal"
dotnet test --filter "FullyQualifiedName~Topic" -f ${{ matrix.dotnet-target-framework }} -l "console;verbosity=normal"
integration-tests:
runs-on: ubuntu-22.04
strategy:
Expand All @@ -134,7 +132,6 @@ jobs:
- 8765:8765
env:
YDB_LOCAL_SURVIVE_RESTART: true
YDB_USE_IN_MEMORY_PDISKS: true
options: '--name ydb-local -h localhost'
env:
OS: ubuntu-22.04
Expand Down
7 changes: 5 additions & 2 deletions src/Ydb.Sdk/src/Ado/PoolManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ internal static class PoolManager
private static readonly SemaphoreSlim SemaphoreSlim = new(1); // async mutex
private static readonly ConcurrentDictionary<string, SessionPool> Pools = new();

internal static async Task<Session> GetSession(YdbConnectionStringBuilder connectionString)
internal static async Task<Session> GetSession(
YdbConnectionStringBuilder connectionString,
CancellationToken cancellationToken
)
{
if (Pools.TryGetValue(connectionString.ConnectionString, out var sessionPool))
{
Expand All @@ -17,7 +20,7 @@ internal static async Task<Session> GetSession(YdbConnectionStringBuilder connec

try
{
await SemaphoreSlim.WaitAsync();
await SemaphoreSlim.WaitAsync(cancellationToken);

if (Pools.TryGetValue(connectionString.ConnectionString, out var pool))
{
Expand Down
26 changes: 14 additions & 12 deletions src/Ydb.Sdk/src/Ado/YdbCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Ydb.Sdk.Ado.Internal;
using Ydb.Sdk.Services.Query;
Expand All @@ -8,9 +9,13 @@ namespace Ydb.Sdk.Ado;

public sealed class YdbCommand : DbCommand
{
private YdbConnection YdbConnection { get; set; }
private YdbConnection? YdbConnection { get; set; }

private string _commandText = string.Empty;
private string? _commandText = string.Empty;

public YdbCommand()
{
}

public YdbCommand(YdbConnection ydbConnection)
{
Expand Down Expand Up @@ -65,14 +70,10 @@ public override void Prepare()

public override string CommandText
{
get => _commandText;
get => _commandText ?? throw new InvalidOperationException("CommandText property has not been initialized");
#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
set
[param: AllowNull] set => _commandText = value;
#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
{
_commandText = value ?? throw new ArgumentNullException(nameof(value));
DbParameterCollection.Clear();
}
}

public override int CommandTimeout
Expand All @@ -99,14 +100,14 @@ protected override DbConnection? DbConnection
get => YdbConnection;
set
{
if (value is YdbConnection ydbConnection)
if (value is null or Ado.YdbConnection)
{
YdbConnection = ydbConnection;
YdbConnection = (YdbConnection?)value;
}
else
{
throw new ArgumentException(
$"Unsupported DbTransaction type: {value?.GetType()}, expected: {typeof(YdbConnection)}");
$"Unsupported DbTransaction type: {value.GetType()}, expected: {typeof(YdbConnection)}");
}
}
}
Expand Down Expand Up @@ -154,7 +155,8 @@ protected override YdbDataReader ExecuteDbDataReader(CommandBehavior behavior)
protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior,
CancellationToken cancellationToken)
{
if (YdbConnection.IsBusy)
if (YdbConnection?.IsBusy
?? throw new InvalidOperationException("Connection property has not been initialized."))
{
throw new YdbOperationInProgressException(YdbConnection);
}
Expand Down
34 changes: 30 additions & 4 deletions src/Ydb.Sdk/src/Ado/YdbConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ public sealed class YdbConnection : DbConnection
{
private static readonly YdbConnectionStringBuilder DefaultSettings = new();

private static readonly StateChangeEventArgs ClosedToOpenEventArgs =
new(ConnectionState.Closed, ConnectionState.Open);

private static readonly StateChangeEventArgs OpenToClosedEventArgs =
new(ConnectionState.Open, ConnectionState.Closed);

private bool _disposed;

private YdbConnectionStringBuilder ConnectionStringBuilder { get; set; }
Expand Down Expand Up @@ -84,18 +90,20 @@ public override async Task OpenAsync(CancellationToken cancellationToken)

try
{
Session = await PoolManager.GetSession(ConnectionStringBuilder);
Session = await PoolManager.GetSession(ConnectionStringBuilder, cancellationToken);
}
catch (Exception e)
{
throw e switch
{
Driver.TransportException transportException => new YdbException(transportException.Status),
StatusUnsuccessfulException unsuccessfulException => new YdbException(unsuccessfulException.Status),
_ => new YdbException("Cannot get session", e)
_ => e
};
}

OnStateChange(ClosedToOpenEventArgs);

ConnectionState = ConnectionState.Open;
}

Expand All @@ -118,6 +126,8 @@ public override async Task CloseAsync()
await LastTransaction.RollbackAsync();
}

OnStateChange(OpenToClosedEventArgs);

ConnectionState = ConnectionState.Closed;
}
finally
Expand All @@ -140,7 +150,9 @@ public override string ConnectionString
}
}

public override string Database => ConnectionStringBuilder.Database;
public override string Database => State == ConnectionState.Closed
? string.Empty
: ConnectionStringBuilder.Database;

public override ConnectionState State => ConnectionState;

Expand All @@ -152,7 +164,16 @@ public override string ConnectionString
internal bool IsBusy => LastReader is { IsClosed: false };

public override string DataSource => string.Empty; // TODO
public override string ServerVersion => string.Empty; // TODO

public override string ServerVersion
{
get
{
EnsureConnectionOpen();

return string.Empty; // TODO ServerVersion
}
}

protected override YdbCommand CreateDbCommand()
{
Expand Down Expand Up @@ -239,6 +260,11 @@ public override async ValueTask DisposeAsync()
_disposed = true;
}

/// <summary>
/// DB provider factory.
/// </summary>
protected override DbProviderFactory DbProviderFactory => YdbProviderFactory.Instance;

/// <summary>
/// Clears the connection pool. All idle physical connections in the pool of the given connection are
/// immediately closed, and any busy connections which were opened before <see cref="ClearPool"/> was called
Expand Down
35 changes: 35 additions & 0 deletions src/Ydb.Sdk/src/Ado/YdbProviderFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Data.Common;

namespace Ydb.Sdk.Ado;

public class YdbProviderFactory : DbProviderFactory
{
public static readonly YdbProviderFactory Instance = new();

public override YdbCommand CreateCommand()
{
return new YdbCommand();
}

public override YdbConnection CreateConnection()
{
return new YdbConnection();
}

public override YdbConnectionStringBuilder CreateConnectionStringBuilder()
{
return new YdbConnectionStringBuilder();
}

public override DbParameter CreateParameter()
{
return new YdbParameter();
}

#if NET7_0_OR_GREATER
public override YdbDataSource CreateDataSource(string connectionString)
{
return new YdbDataSource();
}
#endif
}
51 changes: 51 additions & 0 deletions src/Ydb.Sdk/tests/Ado/Specification/YdbConnectionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using AdoNet.Specification.Tests;
using Xunit;

namespace Ydb.Sdk.Tests.Ado.Specification;

public class YdbConnectionTests : ConnectionTestBase<YdbFactoryFixture>
{
public YdbConnectionTests(YdbFactoryFixture fixture) : base(fixture)
{
}

#pragma warning disable xUnit1004
[Fact(Skip = "IComponent legacy.")]
#pragma warning restore xUnit1004
public override void Dispose_raises_Disposed()
{
base.Dispose_raises_Disposed();
}

#pragma warning disable xUnit1004
[Fact(Skip = "IComponent legacy.")]
#pragma warning restore xUnit1004
public override Task DisposeAsync_raises_Disposed()
{
return base.DisposeAsync_raises_Disposed();
}

#pragma warning disable xUnit1004
[Fact(Skip = "Connect to default settings 'grpc://localhost:2136/local'.")]
#pragma warning restore xUnit1004
public override void Open_throws_when_no_connection_string()
{
base.Open_throws_when_no_connection_string();
}

#pragma warning disable xUnit1004
[Fact(Skip = "TODO Supported this field.")]
#pragma warning restore xUnit1004
public override void ServerVersion_returns_value()
{
base.ServerVersion_returns_value();
}

#pragma warning disable xUnit1004
[Fact(Skip = "TODO Supported cancel OpenAsync.")]
#pragma warning restore xUnit1004
public override Task OpenAsync_is_canceled()
{
return base.OpenAsync_is_canceled();
}
}
12 changes: 12 additions & 0 deletions src/Ydb.Sdk/tests/Ado/Specification/YdbFactoryFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Data.Common;
using AdoNet.Specification.Tests;
using Ydb.Sdk.Ado;

namespace Ydb.Sdk.Tests.Ado.Specification;

public class YdbFactoryFixture : IDbFactoryFixture
{
public DbProviderFactory Factory => YdbProviderFactory.Instance;

public string ConnectionString => "Host=localhost;Port=2136;Database=local";
}
6 changes: 3 additions & 3 deletions src/Ydb.Sdk/tests/Ado/YdbDataReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ public async Task BasedIteration_WhenNotCallMethodRead_ThrowException()
}

[Fact]
public void CreateYdbDataReader_WhenAbortedStatus_ThrowException()
public async Task CreateYdbDataReader_WhenAbortedStatus_ThrowException()
{
var statuses = new List<Status>();
Assert.Equal("Status: Aborted", Assert.Throws<YdbException>(
() => YdbDataReader.CreateYdbDataReader(SingleEnumeratorFailed, statuses.Add).GetAwaiter().GetResult())
Assert.Equal("Status: Aborted", (await Assert.ThrowsAsync<YdbException>(
() => YdbDataReader.CreateYdbDataReader(SingleEnumeratorFailed, statuses.Add)))
.Message);
Assert.Single(statuses);
Assert.Equal(StatusCode.Aborted, statuses[0].StatusCode);
Expand Down
3 changes: 1 addition & 2 deletions src/Ydb.Sdk/tests/Pool/ChannelPoolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ public async Task GetChannel_WhenRaceCondition_ChannelIsCreatedOneTime(bool useA
.Select(endpoint => Task.Run(() => _channelPool.GetChannel(endpoint)))
.ToArray();

// ReSharper disable once CoVariantArrayConversion
Task.WaitAll(tasks);
await Task.WhenAll(tasks);

_mockChannelFactory.Verify(
channelPool => channelPool.CreateChannel(It.IsAny<string>()), Times.Exactly(endpointCount)
Expand Down
5 changes: 3 additions & 2 deletions src/Ydb.Sdk/tests/Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AdoNet.Specification.Tests" Version="2.0.0-beta.2" />
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0-rc.1.23419.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
8 changes: 4 additions & 4 deletions src/Ydb.Sdk/tests/Value/BasicUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ public void ListType()
var elements = value.GetTuple();
Assert.Equal(2, elements.Count);

Assert.Equal(0, elements[0].GetList().Count);
Assert.Empty(elements[0].GetList());
Assert.Equal(new[] { "one", "two" }, elements[1].GetList().Select(v => (string)v!));
}

Expand All @@ -340,9 +340,9 @@ public void TupleType()
});

var elements = value.GetTuple();
Assert.Equal(1, elements.Count);
Assert.Single(elements);

Assert.Equal(0, elements[0].GetTuple().Count);
Assert.Empty(elements[0].GetTuple());
}

[Fact]
Expand All @@ -361,7 +361,7 @@ public void StructType()
var elements = value.GetTuple();
Assert.Equal(2, elements.Count);

Assert.Equal(0, elements[0].GetStruct().Count);
Assert.Empty(elements[0].GetStruct());

var s = elements[1].GetStruct();
Assert.Equal(2, s.Count);
Expand Down
Loading