baseline: OpenMU upstream b5a0961 (fresh source)
This commit is contained in:
302
tests/MUnique.OpenMU.ChatServer.Tests/ChatClientTests.cs
Normal file
302
tests/MUnique.OpenMU.ChatServer.Tests/ChatClientTests.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
// <copyright file="ChatClientTests.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.ChatServer.Tests;
|
||||
|
||||
using System.Buffers;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
using MUnique.OpenMU.Network;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the <see cref="ChatClient"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ChatClientTests
|
||||
{
|
||||
private const string ChatServerHost = "";
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the client joined the room when the authentication was successful.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task AuthenticationSuccessAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe = new DuplexPipe();
|
||||
var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var client = new ChatClient(connection, manager, new NullLogger<ChatClient>());
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
|
||||
var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
Assert.That(room.ConnectedClients, Contains.Item(client));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the authentication fails by providing the wrong token.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task AuthenticationFailedByWrongTokenAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe = new DuplexPipe();
|
||||
var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var client = new ChatClient(connection, manager, new NullLogger<ChatClient>());
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450674"));
|
||||
var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
Assert.That(room.ConnectedClients.Contains(client), Is.False);
|
||||
Assert.That(connection.Connected, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests what happens if two clients try to authenticate with the same token. The first connection should be connected and authenticated, the second disconnected.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task AuthenticationFailedForSecondConnectionAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
var duplexPipe1 = new DuplexPipe();
|
||||
var connection1 = new Connection(duplexPipe1, null, null, new NullLogger<Connection>());
|
||||
var client1 = new ChatClient(connection1, manager, new NullLogger<ChatClient>());
|
||||
await duplexPipe1.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
var duplexPipe2 = new DuplexPipe();
|
||||
var connection2 = new Connection(duplexPipe2, null, null, new NullLogger<Connection>());
|
||||
var client2 = new ChatClient(connection2, manager, new NullLogger<ChatClient>());
|
||||
var disconnectedRaised = false;
|
||||
client2.Disconnected += (_, _) => disconnectedRaised = true;
|
||||
|
||||
await duplexPipe2.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
Assert.That(room.ConnectedClients, Has.Count.EqualTo(1));
|
||||
Assert.That(room.ConnectedClients, Contains.Item(client1));
|
||||
Assert.That(connection2.Connected, Is.False);
|
||||
Assert.That(disconnectedRaised, Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a successful authentication sets the <see cref="IChatClient.Nickname"/>.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task SetNicknameAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe = new DuplexPipe();
|
||||
var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var client = new ChatClient(connection, manager, new NullLogger<ChatClient>());
|
||||
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
Assert.That(client.Nickname, Is.EqualTo("Bob"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a successful authentication sets the <see cref="IChatClient.Index"/>.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task SetClientIndexAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe = new DuplexPipe();
|
||||
var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var client = new ChatClient(connection, manager, new NullLogger<ChatClient>());
|
||||
|
||||
var authInfo = new ChatServerAuthenticationInfo(3, roomId, "Bob", ChatServerHost, "128450673");
|
||||
room!.RegisterClient(authInfo);
|
||||
|
||||
var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
Assert.That(client.Index, Is.EqualTo(authInfo.Index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a message sent to the client gets "encrypted" properly by the XOR-3 key.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task SentMessageEncryptedProperlyAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var duplexPipe = new DuplexPipe();
|
||||
var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var client = new ChatClient(connection, manager, new NullLogger<ChatClient>());
|
||||
var expectedPacket = new byte[] { 0xC1, 0x0B, 0x04, 0x01, 0x06, 0xBD, 0x8E, 0xEA, 0xBD, 0x8E, 0xEA };
|
||||
await client.SendMessageAsync(1, "AAAAAA").ConfigureAwait(false);
|
||||
var sendResult = await duplexPipe.SendPipe.Reader.ReadAsync().ConfigureAwait(false);
|
||||
var sentPacket = sendResult.Buffer.ToArray();
|
||||
Assert.That(sentPacket, Is.EqualTo(expectedPacket));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the room client list is sent property to the client. It should contain the joined client.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task RoomClientListSentAfterJoinAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe = new DuplexPipe();
|
||||
var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var client = new ChatClient(connection, manager, new NullLogger<ChatClient>());
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
|
||||
var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket).ConfigureAwait(false);
|
||||
|
||||
var expectedPacket = new byte[] { 0xC2, 0x00, 0x13, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x42, 0x6F, 0x62, 0, 0, 0, 0, 0, 0, 0 };
|
||||
var readResult = await duplexPipe.SendPipe.Reader.ReadAsync().ConfigureAwait(false);
|
||||
var result = readResult.Buffer.ToArray();
|
||||
Assert.That(result, Is.EquivalentTo(expectedPacket));
|
||||
Assert.That(client.Nickname, Is.EqualTo("Bob"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the room client list is sent to the client which joins as second. It should contain both clients.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task RoomClientListSentForSecondClientAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe1 = new DuplexPipe();
|
||||
var connection1 = new Connection(duplexPipe1, null, null, new NullLogger<Connection>());
|
||||
var client1 = new ChatClient(connection1, manager, new NullLogger<ChatClient>());
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
room.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Alice", ChatServerHost, "94371960"));
|
||||
|
||||
var authenticationPacket1 = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe1.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket1).ConfigureAwait(false);
|
||||
|
||||
var duplexPipe2 = new DuplexPipe();
|
||||
var connection2 = new Connection(duplexPipe2, null, null, new NullLogger<Connection>());
|
||||
var client2 = new ChatClient(connection2, manager, new NullLogger<ChatClient>());
|
||||
var authenticationPacket2 = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xC5, 0xFB, 0x98, 0xCB, 0xFE, 0x92, 0xCA, 0xFF, 0xAB, 0xFC };
|
||||
await duplexPipe2.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket2).ConfigureAwait(false);
|
||||
|
||||
var expectedPacket = new byte[]
|
||||
{
|
||||
0xC2, 0x00, 0x1E, 0x02, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x42, 0x6F, 0x62, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x01, 0x41, 0x6C, 0x69, 0x63, 0x65, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
await duplexPipe2.SendPipe.Writer.WaitForFlushAsync().ConfigureAwait(false);
|
||||
|
||||
var readResult = await duplexPipe2.SendPipe.Reader.ReadAsync().ConfigureAwait(false);
|
||||
var result = readResult.Buffer.ToArray();
|
||||
Assert.That(result, Is.EquivalentTo(expectedPacket));
|
||||
Assert.That(client1.Nickname, Is.EqualTo("Bob"));
|
||||
Assert.That(client2.Nickname, Is.EqualTo("Alice"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the first client gets notified correctly when the second client joins the chat room.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task ClientJoinedPacketSentAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var duplexPipe1 = new DuplexPipe();
|
||||
var connection1 = new Connection(duplexPipe1, null, null, new NullLogger<Connection>());
|
||||
var client1 = new ChatClient(connection1, manager, new NullLogger<ChatClient>());
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
room.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Alice", ChatServerHost, "94371960"));
|
||||
|
||||
var authenticationPacket1 = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await duplexPipe1.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket1).ConfigureAwait(false);
|
||||
|
||||
var duplexPipe2 = new DuplexPipe();
|
||||
var connection2 = new Connection(duplexPipe2, null, null, new NullLogger<Connection>());
|
||||
var client2 = new ChatClient(connection2, manager, new NullLogger<ChatClient>());
|
||||
var authenticationPacket2 = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xC5, 0xFB, 0x98, 0xCB, 0xFE, 0x92, 0xCA, 0xFF, 0xAB, 0xFC };
|
||||
await duplexPipe2.ReceivePipe.Writer.WriteAndWaitForFlushAsync(authenticationPacket2).ConfigureAwait(false);
|
||||
|
||||
var expectedPacket = new byte[]
|
||||
{
|
||||
0xC1, 0x0F, 0x01, 0x00, 0x01, 0x41, 0x6C, 0x69, 0x63, 0x65, 0, 0, 0, 0, 0,
|
||||
}.AsString();
|
||||
|
||||
var readResult = await duplexPipe1.SendPipe.Reader.ReadAsync().ConfigureAwait(false);
|
||||
var received = readResult.Buffer.ToArray().AsString();
|
||||
|
||||
Assert.That(received, Contains.Substring(expectedPacket));
|
||||
Assert.That(client1.Nickname, Is.EqualTo("Bob"));
|
||||
Assert.That(client2.Nickname, Is.EqualTo("Alice"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a call to <see cref="ChatClient.LogOffAsync" /> removes it from the chatroom,
|
||||
/// and the other remaining client gets notified about it.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task ClientLoggedOffAsync()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
var bobsPipe = new DuplexPipe();
|
||||
var bobsClient = new ChatClient(new Connection(bobsPipe, null, null, new NullLogger<Connection>()), manager, new NullLogger<ChatClient>());
|
||||
room!.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", ChatServerHost, "128450673"));
|
||||
room.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Alice", ChatServerHost, "94371960"));
|
||||
|
||||
var bobsAuthPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
|
||||
await bobsPipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(bobsAuthPacket).ConfigureAwait(false);
|
||||
await bobsPipe.ReceivePipe.Writer.WaitForFlushAsync().ConfigureAwait(false);
|
||||
|
||||
var alicePipe = new DuplexPipe();
|
||||
var aliceConnection = new Connection(alicePipe, null, null, new NullLogger<Connection>());
|
||||
var aliceClient = new ChatClient(aliceConnection, manager, new NullLogger<ChatClient>());
|
||||
var aliceAuthPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xC5, 0xFB, 0x98, 0xCB, 0xFE, 0x92, 0xCA, 0xFF, 0xAB, 0xFC };
|
||||
await alicePipe.ReceivePipe.Writer.WriteAndWaitForFlushAsync(aliceAuthPacket).ConfigureAwait(false);
|
||||
|
||||
await bobsClient.LogOffAsync().ConfigureAwait(false);
|
||||
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
|
||||
var expectedPacket = new byte[]
|
||||
{
|
||||
0xC1, 0x0F, 0x01, 0x01, 0x00, 0x42, 0x6F, 0x62, 0, 0, 0, 0, 0, 0, 0,
|
||||
}.AsString();
|
||||
|
||||
await alicePipe.SendPipe.Writer.WaitForFlushAsync().ConfigureAwait(false);
|
||||
|
||||
var readResult = await alicePipe.SendPipe.Reader.ReadAsync().ConfigureAwait(false);
|
||||
var packets = readResult.Buffer.ToArray().AsString();
|
||||
Assert.That(packets, Contains.Substring(expectedPacket));
|
||||
Assert.That(room.ConnectedClients, Has.Count.EqualTo(1));
|
||||
Assert.That(room.ConnectedClients, Contains.Item(aliceClient));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// <copyright file="ChatRoomManagerTests.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.ChatServer.Tests;
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the <see cref="ChatRoomManager"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ChatRoomManagerTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests if the returned roomId by <see cref="ChatRoomManager.CreateChatRoom"/> actually returns a roomId with which the room can be retrieved by <see cref="ChatRoomManager.GetChatRoom"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void RoomCreation()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId = manager.CreateChatRoom();
|
||||
var room = manager.GetChatRoom(roomId);
|
||||
Assert.That(room, Is.Not.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if recurring calls to <see cref="ChatRoomManager.CreateChatRoom"/> return different room ids.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void RoomCreationUniqueIds()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var roomId1 = manager.CreateChatRoom();
|
||||
var roomId2 = manager.CreateChatRoom();
|
||||
|
||||
Assert.That(roomId1, Is.Not.EqualTo(roomId2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a call to <see cref="ChatRoomManager.GetChatRoom"/> with a random room id does not return a room.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetChatRoomNull()
|
||||
{
|
||||
var manager = new ChatRoomManager(new NullLoggerFactory());
|
||||
var room = manager.GetChatRoom(9999);
|
||||
Assert.That(room, Is.Null);
|
||||
}
|
||||
}
|
||||
270
tests/MUnique.OpenMU.ChatServer.Tests/ChatRoomTests.cs
Normal file
270
tests/MUnique.OpenMU.ChatServer.Tests/ChatRoomTests.cs
Normal file
@@ -0,0 +1,270 @@
|
||||
// <copyright file="ChatRoomTests.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.ChatServer.Tests;
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using MUnique.OpenMU.ChatServer;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for the <see cref="ChatRoom"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ChatRoomTests
|
||||
{
|
||||
private const string ChatServerHost = "";
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a new room returns the specified room id, which was given to the constructor.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void RoomId()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
Assert.That(room.RoomId, Is.EqualTo(roomId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to register a client with a different room id. This should fail with an <see cref="ArgumentException"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void RegisterClientWithDifferentRoomId()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId - 1, "Bob", ChatServerHost, "123456789");
|
||||
Assert.Throws<ArgumentException>(() => room.RegisterClient(authenticationInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to register a client with a correct room id.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void RegisterClientWithCorrectRoomId()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
Assert.DoesNotThrow(() => room.RegisterClient(authenticationInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to join a null client. This should fail with an <see cref="ArgumentNullException"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask TryJoinNullClientAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo);
|
||||
Assert.That(async () => await room.TryJoinAsync(null!), Throws.TypeOf<ArgumentNullException>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to join the room with an unauthenticated client. This should fail.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask TryJoinWithUnauthenticatedClientAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo);
|
||||
var chatClient = new Mock<IChatClient>();
|
||||
Assert.That(await room.TryJoinAsync(chatClient.Object).ConfigureAwait(false), Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to join the room with a client with a wrong authentication token. This should fail.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask TryJoinWithAuthenticatedClientButWrongTokenAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo);
|
||||
var chatClient = new Mock<IChatClient>();
|
||||
chatClient.Setup(c => c.AuthenticationToken).Returns("987654321");
|
||||
Assert.That(await room.TryJoinAsync(chatClient.Object).ConfigureAwait(false), Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to join the room with an authenticated client. This should be successful.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask TryJoinWithAuthenticatedClientAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo);
|
||||
var chatClient = new Mock<IChatClient>();
|
||||
chatClient.Setup(c => c.AuthenticationToken).Returns(authenticationInfo.AuthenticationToken);
|
||||
Assert.That(await room.TryJoinAsync(chatClient.Object).ConfigureAwait(false), Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="IChatClient.SendChatRoomClientListAsync"/> is called after a client successfully joined a room.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask ChatRoomClientListSentAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo);
|
||||
var chatClient = new Mock<IChatClient>();
|
||||
chatClient.Setup(c => c.AuthenticationToken).Returns(authenticationInfo.AuthenticationToken);
|
||||
await room.TryJoinAsync(chatClient.Object).ConfigureAwait(false);
|
||||
chatClient.Verify(c => c.SendChatRoomClientListAsync(room.ConnectedClients), Times.Once);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="ChatRoom.ConnectedClients"/> returns the successfully authenticated and joined client.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask ConnectedClientsAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId = room.GetNextClientIndex();
|
||||
var authenticationInfo = new ChatServerAuthenticationInfo(clientId, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo);
|
||||
var chatClient = new Mock<IChatClient>();
|
||||
chatClient.Setup(c => c.AuthenticationToken).Returns(authenticationInfo.AuthenticationToken);
|
||||
await room.TryJoinAsync(chatClient.Object).ConfigureAwait(false);
|
||||
Assert.That(room.ConnectedClients, Has.Count.EqualTo(1));
|
||||
Assert.That(room.ConnectedClients, Contains.Item(chatClient.Object));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="IChatClient.SendChatRoomClientUpdateAsync"/> is called as soon as another client joined the room.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask SendJoinedMessageAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId0 = room.GetNextClientIndex();
|
||||
var clientId1 = room.GetNextClientIndex();
|
||||
var authenticationInfo0 = new ChatServerAuthenticationInfo(clientId0, roomId, "Alice", ChatServerHost, "99999");
|
||||
var authenticationInfo1 = new ChatServerAuthenticationInfo(clientId1, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo0);
|
||||
room.RegisterClient(authenticationInfo1);
|
||||
|
||||
var chatClient0 = new Mock<IChatClient>();
|
||||
chatClient0.SetupAllProperties();
|
||||
chatClient0.Setup(c => c.AuthenticationToken).Returns(authenticationInfo0.AuthenticationToken);
|
||||
var chatClient1 = new Mock<IChatClient>();
|
||||
chatClient1.SetupAllProperties();
|
||||
chatClient1.Setup(c => c.AuthenticationToken).Returns(authenticationInfo1.AuthenticationToken);
|
||||
|
||||
await room.TryJoinAsync(chatClient0.Object).ConfigureAwait(false);
|
||||
await room.TryJoinAsync(chatClient1.Object).ConfigureAwait(false);
|
||||
|
||||
chatClient0.Verify(c => c.SendChatRoomClientUpdateAsync(clientId1, authenticationInfo1.ClientName, ChatRoomClientUpdateType.Joined), Times.Once);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="IChatClient.SendChatRoomClientUpdateAsync"/> is called as soon as another client left the room.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask SendLeftMessageAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId0 = room.GetNextClientIndex();
|
||||
var clientId1 = room.GetNextClientIndex();
|
||||
var authenticationInfo0 = new ChatServerAuthenticationInfo(clientId0, roomId, "Alice", ChatServerHost, "99999");
|
||||
var authenticationInfo1 = new ChatServerAuthenticationInfo(clientId1, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo0);
|
||||
room.RegisterClient(authenticationInfo1);
|
||||
|
||||
var chatClient0 = new Mock<IChatClient>();
|
||||
chatClient0.SetupAllProperties();
|
||||
chatClient0.Setup(c => c.AuthenticationToken).Returns(authenticationInfo0.AuthenticationToken);
|
||||
|
||||
var chatClient1 = new Mock<IChatClient>();
|
||||
chatClient1.SetupAllProperties();
|
||||
chatClient1.Setup(c => c.AuthenticationToken).Returns(authenticationInfo1.AuthenticationToken);
|
||||
|
||||
await room.TryJoinAsync(chatClient0.Object).ConfigureAwait(false);
|
||||
await room.TryJoinAsync(chatClient1.Object).ConfigureAwait(false);
|
||||
|
||||
await room.LeaveAsync(chatClient0.Object).ConfigureAwait(false);
|
||||
chatClient1.Verify(c => c.SendChatRoomClientUpdateAsync(clientId0, authenticationInfo0.ClientName, ChatRoomClientUpdateType.Left), Times.Once);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="IChatClient.SendMessageAsync"/> is called as soon as a message is sent through the room.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask SendMessageAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
const string chatMessage = "foobar1234567890";
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId0 = room.GetNextClientIndex();
|
||||
var clientId1 = room.GetNextClientIndex();
|
||||
var authenticationInfo0 = new ChatServerAuthenticationInfo(clientId0, roomId, "Alice", ChatServerHost, "99999");
|
||||
var authenticationInfo1 = new ChatServerAuthenticationInfo(clientId1, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo0);
|
||||
room.RegisterClient(authenticationInfo1);
|
||||
|
||||
var chatClient0 = new Mock<IChatClient>();
|
||||
chatClient0.Setup(c => c.AuthenticationToken).Returns(authenticationInfo0.AuthenticationToken);
|
||||
|
||||
var chatClient1 = new Mock<IChatClient>();
|
||||
chatClient1.Setup(c => c.AuthenticationToken).Returns(authenticationInfo1.AuthenticationToken);
|
||||
|
||||
await room.TryJoinAsync(chatClient0.Object).ConfigureAwait(false);
|
||||
await room.TryJoinAsync(chatClient1.Object).ConfigureAwait(false);
|
||||
|
||||
await room.SendMessageAsync(clientId1, chatMessage).ConfigureAwait(false);
|
||||
chatClient0.Verify(c => c.SendMessageAsync(clientId1, chatMessage), Times.Once);
|
||||
chatClient1.Verify(c => c.SendMessageAsync(clientId1, chatMessage), Times.Once);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="ChatRoom.RoomClosed"/> is fired as soon as all connected clients left the room.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async ValueTask RoomClosedEventAsync()
|
||||
{
|
||||
const ushort roomId = 4711;
|
||||
var room = new ChatRoom(roomId, new NullLogger<ChatRoom>());
|
||||
var clientId0 = room.GetNextClientIndex();
|
||||
var clientId1 = room.GetNextClientIndex();
|
||||
var authenticationInfo0 = new ChatServerAuthenticationInfo(clientId0, roomId, "Alice", ChatServerHost, "99999");
|
||||
var authenticationInfo1 = new ChatServerAuthenticationInfo(clientId1, roomId, "Bob", ChatServerHost, "123456789");
|
||||
room.RegisterClient(authenticationInfo0);
|
||||
room.RegisterClient(authenticationInfo1);
|
||||
|
||||
var chatClient0 = new Mock<IChatClient>();
|
||||
chatClient0.Setup(c => c.AuthenticationToken).Returns(authenticationInfo0.AuthenticationToken);
|
||||
|
||||
var chatClient1 = new Mock<IChatClient>();
|
||||
chatClient1.Setup(c => c.AuthenticationToken).Returns(authenticationInfo1.AuthenticationToken);
|
||||
|
||||
var eventCalled = false;
|
||||
room.RoomClosed += (sender, e) => eventCalled = true;
|
||||
await room.TryJoinAsync(chatClient0.Object).ConfigureAwait(false);
|
||||
await room.TryJoinAsync(chatClient1.Object).ConfigureAwait(false);
|
||||
await room.LeaveAsync(chatClient0.Object).ConfigureAwait(false);
|
||||
await room.LeaveAsync(chatClient1.Object).ConfigureAwait(false);
|
||||
Assert.That(eventCalled, Is.True);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<WarningsAsErrors>nullable;CS4014;VSTHRD110;VSTHRD100</WarningsAsErrors>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>bin\Debug\MUnique.OpenMU.ChatServer.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>bin\Release\MUnique.OpenMU.ChatServer.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\src\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
|
||||
<Compile Include="..\..\src\SharedGlobalUsings.cs" Link="SharedGlobalUsings.cs" />
|
||||
<Compile Include="..\SharedTestUsings.cs" Link="SharedTestUsings.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\..\src\stylecop.json" Link="stylecop.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="NUnit" />
|
||||
<PackageReference Include="NUnit3TestAdapter" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\ChatServer\MUnique.OpenMU.ChatServer.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
38
tests/MUnique.OpenMU.ChatServer.Tests/PipeWriterExtension.cs
Normal file
38
tests/MUnique.OpenMU.ChatServer.Tests/PipeWriterExtension.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
// <copyright file="PipeWriterExtension.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.ChatServer.Tests;
|
||||
|
||||
using System.IO.Pipelines;
|
||||
|
||||
/// <summary>
|
||||
/// Extensions for the <see cref="PipeWriter"/>, helpful for testing.
|
||||
/// </summary>
|
||||
internal static class PipeWriterExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Flushes and waits until the written bytes are flushed.
|
||||
/// </summary>
|
||||
/// <param name="pipeWriter">The pipe writer.</param>
|
||||
/// <param name="data">The data which should be written.</param>
|
||||
public static async Task WriteAndWaitForFlushAsync(this PipeWriter pipeWriter, ReadOnlyMemory<byte> data)
|
||||
{
|
||||
await pipeWriter.WriteAsync(data).ConfigureAwait(false);
|
||||
await pipeWriter.WaitForFlushAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits until all <see cref="PipeWriter.UnflushedBytes"/> are flushed.
|
||||
/// </summary>
|
||||
/// <param name="pipeWriter">The pipe writer.</param>
|
||||
public static async Task WaitForFlushAsync(this PipeWriter pipeWriter)
|
||||
{
|
||||
do
|
||||
{
|
||||
await Task.Delay(200).ConfigureAwait(false);
|
||||
}
|
||||
while (pipeWriter.UnflushedBytes > 0);
|
||||
await Task.Delay(200).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// <copyright file="AssemblyInfo.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MUnique.OpenMU.ChatServer.Tests")]
|
||||
Reference in New Issue
Block a user