test(upserver): 归档存档迁移与玩法闭环回归工具
This commit is contained in:
20
CodexOutput/upserver/NetworkTransportTests/EngineGlue.cs
Normal file
20
CodexOutput/upserver/NetworkTransportTests/EngineGlue.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using asap.core;
|
||||
namespace asap.core { public interface IConfig { T Get<T>(string key, T fallback); } public interface IEventAggregator {void Publish<T>(T x);Stream<T> GetEvent<T>();} public class EventAggregator:IEventAggregator { readonly Dictionary<Type,object> events=new();public Stream<T> GetEvent<T>(){if(!events.ContainsKey(typeof(T)))events[typeof(T)]=new Stream<T>();return (Stream<T>)events[typeof(T)];} public void Publish<T>(T x)=>GetEvent<T>().Emit(x); } public interface IStageService{Task SwitchStageAsync(string s);} }
|
||||
public class Stream<T> {public event Action<T> Event;public IDisposable Subscribe(Action<T> action){Event+=action;return new Subscription(()=>Event-=action);}public void Emit(T x)=>Event?.Invoke(x);}
|
||||
public class Subscription:IDisposable {Action end;public Subscription(Action a){end=a;}public void Dispose(){end?.Invoke();end=null;}}
|
||||
public static class GContext {static EventAggregator events=new();public static Stream<T> OnEvent<T>()=>events.GetEvent<T>();public static void Publish<T>(T x)=>events.Publish(x);public static Container container=new();}
|
||||
public class Container {public T Resolve<T>()=>default;}
|
||||
namespace game {public class EvtAPISvrLoginSuccess{} public static class QuitStage{public static bool Logout;}}
|
||||
namespace UniRx {} namespace GameCore {}
|
||||
namespace UnityEngine {public static class Debug {public static void Log(object x){Console.WriteLine(x); } public static void LogError(object x){Console.WriteLine("PRODUCTION ERROR: "+x);}public static void LogException(Exception x){if(x is not OperationCanceledException)throw x;}}public class GameObject{public T GetComponent<T>() where T:new()=>new();}}
|
||||
public static class Awaiters { public static Task NextFrame=>Task.CompletedTask; }
|
||||
public class UIManager {public static UIManager Instance=new();public Task<UnityEngine.GameObject> ShowUI(object x)=>Task.FromResult(new UnityEngine.GameObject());}
|
||||
public static class UITypes {public static object NoticeConfirmPopupPanel=new();}
|
||||
public class NoticeConfirmPopupPanel {public void Init(int i,string title,string info,Action onClickLeft,Action onClose,string btn_left_text){}}
|
||||
public static class LocalizationMgr {public static string GetText(string s)=>s;}
|
||||
public static class LoadingScreen {public static Task Show()=>Task.CompletedTask;}
|
||||
|
||||
namespace LitJson {}
|
||||
public static class GConstant {public const string K_Event_API_URL="EventApiURL";}
|
||||
namespace game {public class EvtAPISvrUnauthorized{public int SessionVersion{get;set;}}}
|
||||
class Config(string url):asap.core.IConfig {public T Get<T>(string key,T fallback)=>(T)(object)url;}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net9.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>disable</Nullable><RestoreConfigFile>$(MSBuildThisFileDirectory)../MinimalLoginTests/NuGet.Config</RestoreConfigFile></PropertyGroup><ItemGroup>
|
||||
<Compile Include="../../../Client/Assets/Scripts/Services/RTService.cs"/>
|
||||
<Compile Include="../../../Client/Assets/Scripts/Services/Account/S101AccountSession.cs"/>
|
||||
<Compile Include="../../../Client/Assets/Scripts/Core/CustomServerMgr.cs"/>
|
||||
<Reference Include="Newtonsoft.Json"><HintPath>../../../Client/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.Connections.Abstractions"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.Http.Connections.Client"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.Http.Connections.Common"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Client.Core"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Client"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Common"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.AspNetCore.SignalR.Protocols.Json"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Bcl.TimeProvider"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.Features"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.Options"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll</HintPath></Reference>
|
||||
<Reference Include="Microsoft.Extensions.Primitives"><HintPath>../../../Client/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll</HintPath></Reference>
|
||||
<Reference Include="System.IO.Pipelines"><HintPath>../../../Client/Assets/Plugins/SignalR/System.IO.Pipelines.dll</HintPath></Reference></ItemGroup></Project>
|
||||
59
CodexOutput/upserver/NetworkTransportTests/Program.cs
Normal file
59
CodexOutput/upserver/NetworkTransportTests/Program.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Text.Json;
|
||||
using game.Account;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
var endpoint = new Uri(JsonDocument.Parse(File.ReadAllText("CodexOutput/upserver/network-proxy-address.json")).RootElement.GetProperty("url").GetString());
|
||||
if(endpoint.Host!="127.0.0.1")throw new Exception("Non-loopback fixture");
|
||||
using var control = new HttpClient { Timeout=TimeSpan.FromSeconds(10) };
|
||||
void Check(bool ok,string text){if(!ok)throw new Exception(text);}
|
||||
async Task<JsonElement> Stats()=>JsonDocument.Parse(await control.GetStringAsync(new Uri(endpoint,"__status"))).RootElement;
|
||||
using (var session = new S101AccountSession(endpoint))
|
||||
{
|
||||
foreach(var mode in new[]{"401","reset","timeout"})
|
||||
{
|
||||
await control.GetStringAsync(new Uri(endpoint,"__control?mode="+mode));
|
||||
var started=DateTime.UtcNow;
|
||||
var failed=await session.LoginAsync("102");
|
||||
var elapsed=(DateTime.UtcNow-started).TotalSeconds;
|
||||
var expected=mode=="401"?AccountLoginError.Http:mode=="reset"?AccountLoginError.Network:AccountLoginError.Timeout;
|
||||
Check(failed.Error==expected&&!session.IsAuthenticated&&session.PlayerId==null&&session.InternalId==0,"Failure isolation "+mode+"/"+failed.Error);
|
||||
Check(mode!="401"||failed.StatusCode==401,"Expected status401");
|
||||
Check(mode!="timeout"||elapsed>=14,"Production timeout not reached");
|
||||
var recovered=await session.LoginAsync("102");
|
||||
Check(recovered.Success&&session.IsAuthenticated&&session.PlayerId=="102","Login recovery "+recovered.Error);
|
||||
Check((await session.CheckAuthorizationAsync()).Success,"Recovery cookie rejected");
|
||||
Console.WriteLine($"PASS real HTTP {mode}: {failed.Error}; seconds={elapsed:F1}; retry+authorized readonly Get=OK");
|
||||
}
|
||||
}
|
||||
using var account=new S101AccountSession(endpoint);
|
||||
var mgr=new CustomServerMgr(new Config(endpoint.AbsoluteUri));
|
||||
var rt=new SignalRService(mgr,null);
|
||||
try{
|
||||
Check((await account.LoginAsync("102")).Success,"Hub account login");
|
||||
mgr.UseAccountSession(account);
|
||||
await rt.Connect();
|
||||
Check(rt.IsConnected&&await rt.Publish("Test","acceptance","before")=="OK","Initial hub RPC");
|
||||
var before=await Stats();
|
||||
await control.GetStringAsync(new Uri(endpoint,"__control?mode=drop"));
|
||||
bool observed=false;
|
||||
var deadline=DateTime.UtcNow.AddSeconds(35);
|
||||
while(DateTime.UtcNow<deadline){
|
||||
if(!rt.IsConnected)observed=true;
|
||||
if(observed&&rt.IsConnected)break;
|
||||
await Task.Delay(50);
|
||||
}
|
||||
Check(observed&&rt.IsConnected,"Real socket automatic reconnect");
|
||||
Check(await rt.Publish("Test","acceptance","after")=="OK","Post-reconnect RPC");
|
||||
var after=await Stats();
|
||||
Check(after.GetProperty("upgrades").GetInt32()>before.GetProperty("upgrades").GetInt32(),"No new real websocket upgrade");
|
||||
Check(after.GetProperty("negotiate").GetInt32()==0,"Unexpected negotiate request");
|
||||
Console.WriteLine("PASS real WebSocket dropped, disconnected observed, automatically recovered, Test=OK, negotiate=0");
|
||||
await rt.ReleaseAsync();
|
||||
await Task.Delay(500);
|
||||
var released=await Stats();
|
||||
await Task.Delay(2500);
|
||||
var stable=await Stats();
|
||||
Check(!rt.IsConnected&&stable.GetProperty("active").GetInt32()==0&&stable.GetProperty("upgrades").GetInt32()==released.GetProperty("upgrades").GetInt32(),"Release leaked or reconnected");
|
||||
Console.WriteLine("PASS ReleaseAsync: active sockets=0, no late reconnect");
|
||||
Console.WriteLine("SignalR DLL="+typeof(HubConnection).Assembly.GetName().Version);
|
||||
Console.WriteLine("Fixture counters="+stable.GetRawText());
|
||||
}finally{await rt.ReleaseAsync();mgr.ClearAccountSession();}
|
||||
Reference in New Issue
Block a user