//
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//
using Microsoft.Extensions.Logging.Abstractions;
using MUnique.OpenMU.FriendServer;
namespace MUnique.OpenMU.Tests;
using Moq;
using MUnique.OpenMU.DataModel.Entities;
using MUnique.OpenMU.Interfaces;
using MUnique.OpenMU.Persistence.InMemory;
///
/// Tests for the friend server.
///
[TestFixture]
public sealed class FriendServerTest
{
private Character _player1 = null!;
private Character _player2 = null!;
private Mock _gameServer1 = null!;
private Mock _gameServer2 = null!;
private IFriendServer _friendServer = null!;
private InMemoryPersistenceContextProvider _persistenceContextProvider = null!;
///
/// Sets up the environment with 2 game servers.
///
[SetUp]
public void SetUp()
{
this._gameServer1 = new Mock();
this._gameServer1.Setup(gs => gs.Id).Returns(1);
this._gameServer2 = new Mock();
this._gameServer2.Setup(gs => gs.Id).Returns(2);
var gameServers = new Dictionary
{
{ this._gameServer1.Object.Id, this._gameServer1.Object },
{ this._gameServer2.Object.Id, this._gameServer2.Object },
};
this._persistenceContextProvider = new InMemoryPersistenceContextProvider();
var notifier = new FriendNotifierToGameServer(gameServers); // todo: mock this
this._friendServer = new FriendServer.FriendServer(notifier, new Mock().Object, this._persistenceContextProvider, NullLogger.Instance);
var context = this._persistenceContextProvider.CreateNewContext();
this._player1 = context.CreateNew();
this._player1.Name = "player1";
this._player2 = context.CreateNew();
this._player2.Name = "player2";
}
///
/// Tests what happens when a player adds a friend, while the friend is offline.
/// The player should have a friend list entry.
///
[Test]
public async ValueTask FriendAddRequestOfflineAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
var added = await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
Assert.That(added, Is.True);
this._gameServer2.Verify(g => g.FriendRequestAsync(this._player1.Name, this._player2.Name), Times.Never);
await this.CheckFriendItemsAfterRequestAsync().ConfigureAwait(false);
}
///
/// Tests what happens when a player adds a friend, while the friend is online.
/// The online friend should have got a friend request, the player should have a friend list entry.
///
[Test]
public async ValueTask FriendAddRequestOnlineAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
var added = await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
Assert.That(added, Is.True);
this._gameServer2.Verify(g => g.FriendRequestAsync(this._player1.Name, this._player2.Name), Times.Once);
await this.CheckFriendItemsAfterRequestAsync().ConfigureAwait(false);
}
///
/// Tests if a friend is not added twice when the player sends two friend requests for the same friend.
///
[Test]
public async ValueTask FriendAddRequestRepeatedAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
var added = await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
Assert.That(added, Is.True);
var notAdded = await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
Assert.That(notAdded, Is.False);
this._gameServer2.Verify(g => g.FriendRequestAsync(this._player1.Name, this._player2.Name), Times.Exactly(2));
}
///
/// Tests if both friends have each other in the friend list with visible server number, after the friend accepted friendship.
///
[Test]
public async ValueTask FriendAddRequestAcceptAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
await this._friendServer.FriendResponseAsync(this._player2.Name, this._player1.Name, true).ConfigureAwait(false);
this._gameServer1.Verify(g => g.FriendOnlineStateChangedAsync(this._player1.Name, this._player2.Name, this._gameServer2.Object.Id), Times.AtLeastOnce);
this._gameServer2.Verify(g => g.FriendOnlineStateChangedAsync(this._player2.Name, this._player1.Name, this._gameServer1.Object.Id), Times.AtLeastOnce);
var context = this._persistenceContextProvider.CreateNewFriendServerContext();
var friendItem1 = (await context.GetFriendsAsync(this._player1.Id).ConfigureAwait(false)).FirstOrDefault();
Assert.That(friendItem1, Is.Not.Null);
Assert.That(friendItem1!.CharacterName, Is.EqualTo(this._player1.Name));
Assert.That(friendItem1.FriendName, Is.EqualTo(this._player2.Name));
Assert.That(friendItem1.RequestOpen, Is.False);
Assert.That(friendItem1.Accepted, Is.True);
var friendItem2 = (await context.GetFriendsAsync(this._player2.Id).ConfigureAwait(false)).FirstOrDefault();
Assert.That(friendItem2, Is.Not.Null);
Assert.That(friendItem2!.CharacterName, Is.EqualTo(this._player2.Name));
Assert.That(friendItem2.FriendName, Is.EqualTo(this._player1.Name));
Assert.That(friendItem2.RequestOpen, Is.False);
Assert.That(friendItem2.Accepted, Is.True);
}
///
/// Tests if the player has the friend in his friendlist, but unaccepted.
/// Also checks if the friend which declined, does not get the friend list entry.
///
[Test]
public async ValueTask FriendAddRequestDeclineAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
await this._friendServer.FriendResponseAsync(this._player2.Name, this._player1.Name, false).ConfigureAwait(false);
this._gameServer1.Verify(g => g.FriendOnlineStateChangedAsync(this._player1.Name, this._player2.Name, this._gameServer2.Object.Id), Times.Never);
this._gameServer2.Verify(g => g.FriendOnlineStateChangedAsync(this._player2.Name, this._player1.Name, this._gameServer1.Object.Id), Times.Never);
var context = this._persistenceContextProvider.CreateNewFriendServerContext();
var friendItem = (await context.GetFriendsAsync(this._player1.Id).ConfigureAwait(false)).FirstOrDefault();
Assert.That(friendItem, Is.Not.Null);
Assert.That(friendItem!.CharacterName, Is.EqualTo(this._player1.Name));
Assert.That(friendItem.FriendName, Is.EqualTo(this._player2.Name));
Assert.That(friendItem.RequestOpen, Is.False);
Assert.That(friendItem.Accepted, Is.False);
}
///
/// Tests that a friend response without a corresponding request does not create friend list entries.
///
[Test]
public async ValueTask FriendResponseWithoutRequestAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
await this._friendServer.FriendResponseAsync(this._player2.Name, this._player1.Name, true).ConfigureAwait(false);
this._gameServer1.Verify(g => g.FriendOnlineStateChangedAsync(this._player1.Name, this._player2.Name, this._gameServer2.Object.Id), Times.Never);
this._gameServer2.Verify(g => g.FriendOnlineStateChangedAsync(this._player2.Name, this._player1.Name, this._gameServer1.Object.Id), Times.Never);
}
///
/// Tests if a friend can get deleted from the friend list, but the friend still has the player.
///
[Test]
public async ValueTask FriendDeleteAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
await this._friendServer.FriendResponseAsync(this._player2.Name, this._player1.Name, true).ConfigureAwait(false);
await this._friendServer.DeleteFriendAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
this._gameServer2.Verify(g => g.FriendOnlineStateChangedAsync(this._player2.Name, this._player1.Name, FriendServer.FriendServer.OfflineServerId), Times.Once);
}
///
/// Here is tested if the notifications between players in the friend list are working properly.
/// Is is tested with 2 players in 2 different gameservers.
/// player1 on gameServer1
/// player2 on gameServer2.
///
[Test]
public async ValueTask TestOnlineListAsync()
{
await this.PlayerEnteredGameAsync(this._player1.Id, this._player1.Name, this._gameServer1.Object.Id).ConfigureAwait(false);
await this.PlayerEnteredGameAsync(this._player2.Id, this._player2.Name, this._gameServer2.Object.Id).ConfigureAwait(false);
await this._friendServer.FriendRequestAsync(this._player1.Name, this._player2.Name).ConfigureAwait(false);
await this._friendServer.FriendResponseAsync(this._player2.Name, this._player1.Name, true).ConfigureAwait(false);
await this._friendServer.PlayerLeftGameAsync(this._player1.Id, this._player1.Name).ConfigureAwait(false);
await this._friendServer.PlayerLeftGameAsync(this._player2.Id, this._player2.Name).ConfigureAwait(false);
this._gameServer1.Invocations.Clear();
this._gameServer2.Invocations.Clear();
await this._friendServer.PlayerEnteredGameAsync((byte)this._gameServer1.Object.Id, this._player1.Id, this._player1.Name).ConfigureAwait(false);
await this._friendServer.PlayerEnteredGameAsync((byte)this._gameServer2.Object.Id, this._player2.Id, this._player2.Name).ConfigureAwait(false);
this._gameServer1.Verify(gs => gs.FriendOnlineStateChangedAsync(this._player1.Name, this._player2.Name, this._gameServer2.Object.Id), Times.AtLeastOnce);
await this._friendServer.PlayerLeftGameAsync(this._player1.Id, this._player1.Name).ConfigureAwait(false);
this._gameServer2.Verify(gs => gs.FriendOnlineStateChangedAsync(this._player2.Name, this._player1.Name, FriendServer.FriendServer.OfflineServerId), Times.AtLeastOnce);
}
private async ValueTask PlayerEnteredGameAsync(Guid playerId, string playerName, int serverId)
{
await this._friendServer.PlayerEnteredGameAsync((byte)serverId, playerId, playerName).ConfigureAwait(false);
}
private async ValueTask CheckFriendItemsAfterRequestAsync()
{
var context = this._persistenceContextProvider.CreateNewFriendServerContext();
var friendItem = (await context.GetFriendsAsync(this._player1.Id).ConfigureAwait(false)).FirstOrDefault();
Assert.That(friendItem, Is.Not.Null);
Assert.That(friendItem!.CharacterName, Is.EqualTo(this._player1.Name));
Assert.That(friendItem.FriendName, Is.EqualTo(this._player2.Name));
Assert.That(friendItem.RequestOpen, Is.True);
Assert.That(friendItem.Accepted, Is.False);
}
}