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
2 changes: 0 additions & 2 deletions kx.Benchmark.Test/kx.Benchmark.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
6 changes: 4 additions & 2 deletions kx.Test/Connection/ConnectionSerialisationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace kx.Test.Connection
[TestFixture]
public class ConnectionSerialisationTests
{
private static readonly string[] Keys = {"Key_1"};
private static readonly object[] Values = {"Value_1"};
private readonly int _testVersionNumber = 3;

[Test]
Expand Down Expand Up @@ -402,7 +404,7 @@ public void ConnectionSerialisesAndDeserialisesTimeSpanInput()
[Test]
public void ConnectionSerialisesAndDeserialisesDictInput()
{
c.Dict expected = new c.Dict(new string[] { "Key_1" }, new object[] { "Value_1" });
c.Dict expected = new c.Dict(Keys, Values);

using (var connection = new c(_testVersionNumber))
{
Expand All @@ -419,7 +421,7 @@ public void ConnectionSerialisesAndDeserialisesDictInput()
[Test]
public void ConnectionSerialisesAndDeserialisesFlipInput()
{
c.Flip expected = new c.Flip(new c.Dict(new string[] { "Key_1" }, new object[] { "Value_1" }));
c.Flip expected = new c.Flip(new c.Dict(Keys, Values));

using (var connection = new c(_testVersionNumber))
{
Expand Down
154 changes: 154 additions & 0 deletions kx.Test/Connection/ConnectionTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using kx.Test.TestUtils;
using NUnit.Framework;

Expand Down Expand Up @@ -86,5 +89,156 @@ public void ConnectionThrowsSerialisableExpectionIfAuthenticationDoesNotPass()
Assert.IsNotNull(error);
}
}

[Test]
public void ProtectedConstructorAndBufferStateAreAccessibleToDerivedTypes()
{
using (var connection = new TestConnection())
{
Assert.IsNull(connection.ExposedReadBuffer);
Assert.IsFalse(connection.ExposedIsLittleEndian);
Assert.AreEqual(0, connection.ExposedReadPosition);

connection.ExposedReadPosition = 3;
Assert.AreEqual(3, connection.ExposedReadPosition);
Assert.Throws<ArgumentOutOfRangeException>(() => connection.ExposedReadPosition = -1);
}
}

[Test]
public void DisposeCanBeCalledMoreThanOnce()
{
var connection = new c(new MemoryStream());

connection.Dispose();

Assert.DoesNotThrow(connection.Dispose);
}

[Test]
public void CloseClosesBothStreamAndSocket()
{
using (var server = new TestableTcpServer())
{
var connection = new c("localhost", server.TestPort);

Assert.DoesNotThrow(connection.Close);
connection.Dispose();
}
}

[Test]
public void ExplicitTlsOptionsConstructorAcceptsNullAsDisabled()
{
using (var server = new TestableTcpServer())
using (var connection = new c("localhost", server.TestPort, Environment.UserName, 1024, null))
{
Assert.IsNotNull(connection);
}
}

[Test]
public async Task ParameterlessAsyncReadReturnsDeserialisedObject()
{
const int expected = 42;
byte[] message;
using (var serializer = new c(3))
{
message = serializer.Serialize(1, expected);
}

using (var stream = new MemoryStream(message))
using (var connection = new c(stream))
{
Assert.AreEqual(expected, await connection.kAsync());
}
}

[Test]
public async Task ParameterlessAsyncHeaderReadPopulatesReadableBuffer()
{
const int expected = 42;
byte[] message;
using (var serializer = new c(3))
{
message = serializer.Serialize(1, expected);
}

using (var stream = new MemoryStream(message))
using (var connection = new TestConnection(stream))
{
await connection.k0Async();

Assert.AreEqual(expected, connection.ExposedReadObject());
}
}

[TestCase(1)]
[TestCase(2)]
public async Task ParameterlessAsyncMessageWritesExpectedMessageType(int messageType)
{
const string expected = "payload";
using (var stream = new MemoryStream())
using (var connection = new c(stream))
{
if (messageType == 1)
{
await connection.knAsync(expected);
}
else
{
await connection.krAsync(expected);
}

byte[] message = stream.ToArray();
Assert.AreEqual(messageType, message[1]);
Assert.AreEqual(expected, connection.Deserialize(message));
}
}

[Test]
public async Task ProtectedParameterlessWriteAsyncWritesRequestedBytes()
{
byte[] expected = { 1, 2, 3, 4 };
using (var stream = new MemoryStream())
using (var connection = new TestConnection(stream))
{
await connection.ExposedWriteAsync(expected, expected.Length);

Assert.IsTrue(expected.SequenceEqual(stream.ToArray()));
}
}

private sealed class TestConnection : c
{
internal TestConnection()
{
}

internal TestConnection(Stream stream)
: base(stream)
{
}

internal byte[] ExposedReadBuffer => ReadBuffer;

internal int ExposedReadPosition
{
get => ReadPosition;
set => ReadPosition = value;
}

internal bool ExposedIsLittleEndian => IsLittleEndian;

internal object ExposedReadObject()
{
return ReadObject();
}

internal Task ExposedWriteAsync(byte[] bytes, int number)
{
return WriteAsync(bytes, number);
}
}
}
}
40 changes: 40 additions & 0 deletions kx.Test/Connection/KExceptionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using NUnit.Framework;

namespace kx.Test.Connection
{
[TestFixture]
public class KExceptionTests
{
[Test]
public void DefaultConstructorCreatesExceptionWithDefaultMessage()
{
var exception = new KException();

Assert.IsNull(exception.InnerException);
Assert.IsNotEmpty(exception.Message);
}

[Test]
public void MessageConstructorPreservesMessage()
{
const string expected = "kdb error";

var exception = new KException(expected);

Assert.AreEqual(expected, exception.Message);
}

[Test]
public void InnerExceptionConstructorPreservesMessageAndCause()
{
const string expected = "serialization failed";
var cause = new InvalidOperationException("cause");

var exception = new KException(expected, cause);

Assert.AreEqual(expected, exception.Message);
Assert.AreSame(cause, exception.InnerException);
}
}
}
3 changes: 3 additions & 0 deletions kx/c.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/// This class is essentially a serializer/deserializer of .NET types
/// to/from the KDB+ IPC wire format, enabling remote method invocation in KDB+ via TCP/IP.
/// </remarks>
public class c : IDisposable

Check warning on line 22 in kx/c.cs

View workflow job for this annotation

GitHub Actions / build

The type name 'c' only contains lower-cased ascii characters. Such names may become reserved for the language.

Check warning on line 22 in kx/c.cs

View workflow job for this annotation

GitHub Actions / build

The type name 'c' only contains lower-cased ascii characters. Such names may become reserved for the language.
{
private readonly Socket _socket;

Expand Down Expand Up @@ -369,6 +369,7 @@
/// </remarks>
protected c()
{
_maxBufferSize = DefaultMaxBufferSize;
_versionNumber = 3;
}

Expand All @@ -382,6 +383,7 @@
/// </remarks>
internal c(int versionNumber)
{
_maxBufferSize = DefaultMaxBufferSize;
_versionNumber = versionNumber;
}

Expand Down Expand Up @@ -411,6 +413,7 @@
internal c(Stream clientStream, int versionNumber)
{
_clientStream = clientStream;
_maxBufferSize = DefaultMaxBufferSize;
_versionNumber = versionNumber;
}

Expand Down