diff --git a/kx.Benchmark.Test/kx.Benchmark.Test.csproj b/kx.Benchmark.Test/kx.Benchmark.Test.csproj index 2f9a120..d5d49b3 100644 --- a/kx.Benchmark.Test/kx.Benchmark.Test.csproj +++ b/kx.Benchmark.Test/kx.Benchmark.Test.csproj @@ -21,8 +21,6 @@ - - diff --git a/kx.Test/Connection/ConnectionSerialisationTests.cs b/kx.Test/Connection/ConnectionSerialisationTests.cs index b8655bc..199a727 100644 --- a/kx.Test/Connection/ConnectionSerialisationTests.cs +++ b/kx.Test/Connection/ConnectionSerialisationTests.cs @@ -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] @@ -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)) { @@ -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)) { diff --git a/kx.Test/Connection/ConnectionTests.cs b/kx.Test/Connection/ConnectionTests.cs index 6a41a5a..57b8f66 100644 --- a/kx.Test/Connection/ConnectionTests.cs +++ b/kx.Test/Connection/ConnectionTests.cs @@ -1,4 +1,7 @@ using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; using kx.Test.TestUtils; using NUnit.Framework; @@ -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(() => 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); + } + } } } diff --git a/kx.Test/Connection/KExceptionTests.cs b/kx.Test/Connection/KExceptionTests.cs new file mode 100644 index 0000000..d2f5c30 --- /dev/null +++ b/kx.Test/Connection/KExceptionTests.cs @@ -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); + } + } +} diff --git a/kx/c.cs b/kx/c.cs index a8db7a8..ddb47d1 100644 --- a/kx/c.cs +++ b/kx/c.cs @@ -369,6 +369,7 @@ public c( /// protected c() { + _maxBufferSize = DefaultMaxBufferSize; _versionNumber = 3; } @@ -382,6 +383,7 @@ protected c() /// internal c(int versionNumber) { + _maxBufferSize = DefaultMaxBufferSize; _versionNumber = versionNumber; } @@ -411,6 +413,7 @@ internal c(Stream clientStream) internal c(Stream clientStream, int versionNumber) { _clientStream = clientStream; + _maxBufferSize = DefaultMaxBufferSize; _versionNumber = versionNumber; }