mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-27 07:59:03 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RadicadeServer.API.Rooms;
|
||||
using RadicadeServer.API.Rooms.Currency.V1;
|
||||
using RadicadeServer.API.Rooms.Keys.V1;
|
||||
using RadicadeServer.DB;
|
||||
using RadicadeServer.RecNet.Accounts;
|
||||
using RadicadeServer.RecNet.Rooms;
|
||||
using Xunit;
|
||||
|
||||
namespace RadicadeServer.Tests;
|
||||
|
||||
public class RoomEconomyPersistenceTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task CurrencyAndConsumableCreationPersistForTheCurrentRoom()
|
||||
{
|
||||
var options = TestDbOptions.Create()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
await using var db = new RecDBContext(options);
|
||||
const long accountId = 71;
|
||||
const long roomId = 902;
|
||||
var instance = new RoomInstance { roomId = roomId };
|
||||
db.RoomInstances.Add(instance);
|
||||
db.Presences.Add(new RealPresence
|
||||
{
|
||||
playerId = accountId,
|
||||
isOnline = true,
|
||||
roomInstance = instance.roomInstanceId,
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var currencyApi = new RoomCurrencyAPI(db);
|
||||
SetUserAndJsonBody(currencyApi, accountId, "{\"Name\":\"Test currency\",\"Description\":\"A test currency\",\"Color\":\"#112233\"}");
|
||||
var currencyResult = Assert.IsType<OkObjectResult>(await currencyApi.CreateCurrency());
|
||||
var currency = Assert.IsType<Dictionary<string, object?>>(currencyResult.Value);
|
||||
Assert.Equal(roomId, currency["RoomId"]);
|
||||
Assert.Equal("#112233", currency["Color"]);
|
||||
|
||||
var consumableApi = new RoomConsumablesAPI(db);
|
||||
SetUserAndJsonBody(consumableApi, accountId, "{\"Name\":\"Test consumable\",\"Description\":\"A test consumable\"}");
|
||||
var consumableResult = Assert.IsType<OkObjectResult>(await consumableApi.CreateRoomConsumable());
|
||||
var consumable = Assert.IsType<Dictionary<string, object?>>(consumableResult.Value);
|
||||
Assert.Equal(roomId, consumable["RoomId"]);
|
||||
|
||||
var listedCurrency = Assert.IsType<OkObjectResult>(await currencyApi.GetRoomCurrencies(roomId));
|
||||
var listedCurrencies = Assert.IsType<List<Dictionary<string, object?>>>(listedCurrency.Value);
|
||||
Assert.Single(listedCurrencies);
|
||||
Assert.Equal(currency["CurrencyId"], listedCurrencies[0]["CurrencyId"]);
|
||||
|
||||
var listedConsumable = Assert.IsType<OkObjectResult>(await consumableApi.GetRoomConsumablesInRoom(roomId));
|
||||
var listedConsumables = Assert.IsType<List<Dictionary<string, object?>>>(listedConsumable.Value);
|
||||
Assert.Single(listedConsumables);
|
||||
Assert.Equal(consumable["ConsumableId"], listedConsumables[0]["ConsumableId"]);
|
||||
|
||||
var storedConfig = await db.ServerConfig.SingleAsync(config => config.Key == "RoomAssets");
|
||||
Assert.Contains("Test currency", storedConfig.Value);
|
||||
Assert.Contains("Test consumable", storedConfig.Value);
|
||||
|
||||
// The list routes load records from persisted JSON, not the original request
|
||||
// dictionaries; nested JSON values must remain intact after deserialization.
|
||||
await using var restartedDb = new RecDBContext(options);
|
||||
var reloadedCurrencies = Assert.IsType<OkObjectResult>(
|
||||
await new RoomCurrencyAPI(restartedDb).GetRoomCurrencies(roomId));
|
||||
var reloadedCurrency = Assert.Single(
|
||||
Assert.IsAssignableFrom<IEnumerable<Dictionary<string, object?>>>(reloadedCurrencies.Value));
|
||||
Assert.Equal("#112233", reloadedCurrency["Color"]?.ToString());
|
||||
|
||||
var reloadedConsumables = Assert.IsType<OkObjectResult>(
|
||||
await new RoomConsumablesAPI(restartedDb).GetRoomConsumablesInRoom(roomId));
|
||||
Assert.Equal("Test consumable",
|
||||
Assert.Single(Assert.IsAssignableFrom<IEnumerable<Dictionary<string, object?>>>(reloadedConsumables.Value))["Name"]?.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RoomKeyCreationUsesTheCurrentRoomAndPersistsTheKey()
|
||||
{
|
||||
var options = TestDbOptions.Create()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
await using var db = new RecDBContext(options);
|
||||
const long accountId = 81;
|
||||
const long roomId = 903;
|
||||
var instance = new RoomInstance { roomId = roomId };
|
||||
db.RoomInstances.Add(instance);
|
||||
db.Presences.Add(new RealPresence
|
||||
{
|
||||
playerId = accountId,
|
||||
isOnline = true,
|
||||
roomInstance = instance.roomInstanceId,
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var api = new RoomKeysAPI(db);
|
||||
SetUserAndJsonBody(api, accountId, "{\"Name\":\"Test key\",\"Description\":\"A test key\",\"Price\":5}");
|
||||
|
||||
var created = Assert.IsType<OkObjectResult>(await api.CreateRoomKey());
|
||||
var key = Assert.IsType<RoomKey>(created.Value);
|
||||
Assert.Equal(roomId, key.RoomId);
|
||||
Assert.Equal("Test key", key.Name);
|
||||
Assert.Equal(key.RoomKeyId, Assert.Single(db.RoomKeys).RoomKeyId);
|
||||
var listed = Assert.IsType<OkObjectResult>(api.GetRoomKeysForRoom(roomId));
|
||||
Assert.Equal(key.RoomKeyId, Assert.Single(Assert.IsAssignableFrom<IEnumerable<RoomKey>>(listed.Value)).RoomKeyId);
|
||||
var missingRoomId = Assert.IsType<OkObjectResult>(api.GetRoomKeysForRoom(null));
|
||||
Assert.Empty(Assert.IsAssignableFrom<IEnumerable<RoomKey>>(missingRoomId.Value));
|
||||
|
||||
// The client endpoint takes the RoomKeyId in its path and answers a bare bool.
|
||||
// Creating a room key doesn't purchase it; model ownership explicitly.
|
||||
db.Unlocks.Add(new PlayerUnlocks
|
||||
{
|
||||
AccountId = accountId,
|
||||
RoomKeys = JsonSerializer.Serialize(new[] { key.RoomKeyId })
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
SetUserAndJsonBody(api, accountId, string.Empty);
|
||||
Assert.True(Assert.IsType<bool>(Assert.IsType<OkObjectResult>(await api.IsRoomKeyPurchased(key.RoomKeyId)).Value));
|
||||
Assert.False(Assert.IsType<bool>(Assert.IsType<OkObjectResult>(await api.IsRoomKeyPurchased(key.RoomKeyId + 1000)).Value));
|
||||
Assert.False(Assert.IsType<bool>(Assert.IsType<OkObjectResult>(await api.IsRoomKeyPurchased(key.RoomKeyId + 1)).Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BalanceLookupsAnswerWithAZeroBalanceRatherThanNotFound()
|
||||
{
|
||||
// The 2023 client asks getBalance right after getAllBalances on every room join and
|
||||
// retries an answer it cannot use, so a 404 here is a join that spends a fresh TLS
|
||||
// connection and a round trip (~100 ms RTT) per retry before the room finishes
|
||||
// loading. This server tracks no balances, so the answer is a zero balance.
|
||||
var options = TestDbOptions.Create()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||
.Options;
|
||||
using var db = new RecDBContext(options);
|
||||
|
||||
var api = new RoomCurrencyAPI(db);
|
||||
SetUserAndJsonBody(api, 91, "{}");
|
||||
|
||||
var result = Assert.IsType<OkObjectResult>(api.GetBalance("d0618354-d68a-4364-a693-b8cf09879973", 91, 25));
|
||||
var balance = JsonDocument.Parse(JsonSerializer.Serialize(result.Value)).RootElement;
|
||||
Assert.Equal("d0618354-d68a-4364-a693-b8cf09879973", balance.GetProperty("CurrencyId").GetString());
|
||||
Assert.Equal(91, balance.GetProperty("AccountId").GetInt64());
|
||||
Assert.Equal(25, balance.GetProperty("RoomId").GetInt64());
|
||||
Assert.Equal(0, balance.GetProperty("Balance").GetInt32());
|
||||
|
||||
// The client does not always send the account it is asking about; the caller's own
|
||||
// id is the only sensible substitute.
|
||||
var anonymous = new RoomCurrencyAPI(db);
|
||||
SetUserAndJsonBody(anonymous, 92, "{}");
|
||||
var inferred = Assert.IsType<OkObjectResult>(anonymous.GetBalance(null, null, null));
|
||||
var inferredBalance = JsonDocument.Parse(JsonSerializer.Serialize(inferred.Value)).RootElement;
|
||||
Assert.Equal(92, inferredBalance.GetProperty("AccountId").GetInt64());
|
||||
Assert.Equal(string.Empty, inferredBalance.GetProperty("CurrencyId").GetString());
|
||||
}
|
||||
|
||||
private static void SetUserAndJsonBody(Controller controller, long accountId, string json)
|
||||
{
|
||||
var identity = new ClaimsIdentity("TestAuth");
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, accountId.ToString()));
|
||||
var request = new DefaultHttpContext { User = new ClaimsPrincipal(identity) }.Request;
|
||||
request.ContentType = "application/json";
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
||||
request.ContentLength = request.Body.Length;
|
||||
controller.ControllerContext = new ControllerContext { HttpContext = request.HttpContext };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user