using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; using LBPUnion.ProjectLighthouse.Tests.Helpers; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; using Microsoft.AspNetCore.Mvc; using Xunit; namespace ProjectLighthouse.Tests.GameApiTests.Unit.Controllers; [Trait("Category", "Unit")] public class SlotControllerTests { #region SlotsBy [Fact] public async Task SlotsBy_ShouldReturnNotFound_WhenUserInvalid() { DatabaseContext db = await MockHelper.GetTestDatabase(); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.SlotsBy("bytest"); Assert.IsType(result); } [Fact] public async Task SlotsBy_ShouldFetchLevelsByUser() { List slots = new() { new SlotEntity { SlotId = 1, CreatorId = 2, }, new SlotEntity { SlotId = 2, CreatorId = 2, }, new SlotEntity { SlotId = 3, CreatorId = 3, }, }; List users = new() { new UserEntity { Username = "bytest", UserId = 2, }, new UserEntity { Username = "user3", UserId = 3, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots, users); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.SlotsBy("bytest"); const int expectedElements = 2; HashSet expectedSlotIds = new(){1, 2,}; GenericSlotResponse slotResponse = result.CastTo(); Assert.Equal(expectedElements, slotResponse.Slots.Count); Assert.Equal(expectedSlotIds, slotResponse.Slots.OfType().Select(s => s.SlotId).ToHashSet()); } [Fact] public async Task SlotsBy_ResultsAreOrderedByFirstUploadedTimestampAscending() { List slots = new() { new SlotEntity { SlotId = 1, CreatorId = 2, FirstUploaded = 3, }, new SlotEntity { SlotId = 2, CreatorId = 2, FirstUploaded = 1, }, new SlotEntity { SlotId = 3, CreatorId = 2, FirstUploaded = 2, }, }; List users = new() { new UserEntity { Username = "bytest", UserId = 2, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots, users); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.SlotsBy("bytest"); const int expectedElements = 3; const int expectedFirstSlotId = 2; const int expectedSecondSlotId = 3; const int expectedThirdSlotId = 1; GenericSlotResponse slotResponse = result.CastTo(); Assert.Equal(expectedElements, slotResponse.Slots.Count); Assert.Equal(expectedFirstSlotId, ((GameUserSlot)slotResponse.Slots[0]).SlotId); Assert.Equal(expectedSecondSlotId, ((GameUserSlot)slotResponse.Slots[1]).SlotId); Assert.Equal(expectedThirdSlotId, ((GameUserSlot)slotResponse.Slots[2]).SlotId); } #endregion #region UserSlot [Fact] public async Task UserSlot_ShouldFetch_WhenSlotIsValid() { List slots = new() { new SlotEntity { CreatorId = 1, SlotId = 2, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(2); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldNotFetch_WhenGameVersionMismatch() { List slots = new() { new SlotEntity { CreatorId = 1, SlotId = 2, GameVersion = GameVersion.LittleBigPlanet2, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(2); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldFetch_WhenGameVersionEqual() { GameTokenEntity token = MockHelper.GetUnitTestToken(); token.GameVersion = GameVersion.LittleBigPlanetVita; List tokens = new() { token, }; List slots = new() { new SlotEntity { SlotId = 2, CreatorId = 1, GameVersion = GameVersion.LittleBigPlanetVita, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots, tokens); SlotsController slotsController = new(db); slotsController.SetupTestController(token); IActionResult result = await slotsController.UserSlot(2); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldFetch_WhenGameVersionIsGreater() { GameTokenEntity token = MockHelper.GetUnitTestToken(); token.GameVersion = GameVersion.LittleBigPlanet3; List tokens = new() { token, }; List slots = new() { new SlotEntity { SlotId = 2, CreatorId = 1, GameVersion = GameVersion.LittleBigPlanet1, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots, tokens); SlotsController slotsController = new(db); slotsController.SetupTestController(token); IActionResult result = await slotsController.UserSlot(2); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldReturnNotFound_WhenSlotDoesNotExist() { DatabaseContext db = await MockHelper.GetTestDatabase(); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(20); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldFetch_WhenSlotIsNotSubLevel() { List slots = new() { new SlotEntity { SlotId = 27, CreatorId = 1, SubLevel = false, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(27); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldNotFetch_WhenSlotIsHidden() { List slots = new() { new SlotEntity { SlotId = 27, CreatorId = 1, Hidden = true, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(27); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldNotFetch_WhenSlotIsWrongType() { List slots = new() { new SlotEntity { SlotId = 27, CreatorId = 1, Type = SlotType.Developer, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(27); Assert.IsType(result); } [Fact] public async Task UserSlot_ShouldFetch_WhenSlotIsSubLevel() { List slots = new() { new SlotEntity { SlotId = 27, CreatorId = 1, SubLevel = true, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController slotsController = new(db); slotsController.SetupTestController(); IActionResult result = await slotsController.UserSlot(27); Assert.IsType(result); } #endregion #region DeveloperSlot [Fact] public async Task DeveloperSlot_ShouldFetch_WhenSlotIdIsValid() { List slots = new() { new SlotEntity { SlotId = 1, CreatorId = 1, InternalSlotId = 25, Type = SlotType.Developer, }, }; DatabaseContext db = await MockHelper.GetTestDatabase(slots); SlotsController controller = new(db); controller.SetupTestController(); IActionResult result = await controller.DeveloperSlot(25); Assert.IsType(result); } [Fact] public async Task DeveloperSlot_ShouldFetch_WhenSlotIdIsInvalid() { DatabaseContext db = await MockHelper.GetTestDatabase(); SlotsController controller = new(db); controller.SetupTestController(); IActionResult result = await controller.DeveloperSlot(26); Assert.IsType(result); } #endregion #region BusiestLevels // Rather than trying to mock a singleton // we just make the unit tests take turns private static readonly Mutex roomMutex = new(false); private static async Task AddRoom(int slotId, SlotType type, params int[] playerIds) { await RoomHelper.Rooms.AddAsync(new Room { PlayerIds = new List(playerIds), Slot = new RoomSlot { SlotId = slotId, SlotType = type, }, }); } [Fact] public async Task BusiestLevels_ShouldReturnSlots_OrderedByRoomCount() { roomMutex.WaitOne(); try { DatabaseContext db = await MockHelper.GetTestDatabase(new List { new() { SlotId = 1, CreatorId = 1, Type = SlotType.User, }, new() { SlotId = 2, CreatorId = 1, Type = SlotType.User, }, new() { SlotId = 3, CreatorId = 1, Type = SlotType.User, }, new() { SlotId = 4, CreatorId = 1, Type = SlotType.Developer, InternalSlotId = 10, }, }); SlotsController controller = new(db); controller.SetupTestController(); await AddRoom(1, SlotType.User, 1); await AddRoom(2, SlotType.User, 2); await AddRoom(2, SlotType.User, 3); await AddRoom(3, SlotType.User, 4); await AddRoom(3, SlotType.User, 5); await AddRoom(3, SlotType.User, 6); await AddRoom(10, SlotType.Developer, 7); IActionResult result = await controller.BusiestLevels(); GenericSlotResponse slotResponse = result.CastTo(); Assert.Equal(3, slotResponse.Slots.Count); Assert.IsType(slotResponse.Slots[0]); Assert.Equal(3, ((GameUserSlot)slotResponse.Slots[0]).SlotId); Assert.IsType(slotResponse.Slots[1]); Assert.Equal(2, ((GameUserSlot)slotResponse.Slots[1]).SlotId); Assert.IsType(slotResponse.Slots[2]); Assert.Equal(1, ((GameUserSlot)slotResponse.Slots[2]).SlotId); } finally { roomMutex.ReleaseMutex(); } } [Fact] public async Task BusiestLevels_ShouldNotIncludeDeveloperSlots() { roomMutex.WaitOne(); try { DatabaseContext db = await MockHelper.GetTestDatabase(new List { new() { SlotId = 4, CreatorId = 1, Type = SlotType.Developer, InternalSlotId = 10, }, }); SlotsController controller = new(db); controller.SetupTestController(); await AddRoom(10, SlotType.Developer, 1); IActionResult result = await controller.BusiestLevels(); GenericSlotResponse slotResponse = result.CastTo(); Assert.Empty(slotResponse.Slots); } finally { roomMutex.ReleaseMutex(); } } [Fact] public async Task BusiestLevels_ShouldNotIncludeInvalidSlots() { roomMutex.WaitOne(); try { DatabaseContext db = await MockHelper.GetTestDatabase(); SlotsController controller = new(db); controller.SetupTestController(); await AddRoom(1, SlotType.User, 1); IActionResult result = await controller.BusiestLevels(); GenericSlotResponse slotResponse = result.CastTo(); Assert.Empty(slotResponse.Slots); } finally { roomMutex.ReleaseMutex(); } } #endregion }