test(upserver): 归档存档迁移与玩法闭环回归工具
This commit is contained in:
40
CodexOutput/upserver/KVGameplayLoopTests/Program.cs
Normal file
40
CodexOutput/upserver/KVGameplayLoopTests/Program.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
var root=Path.GetFullPath(Path.Combine("CodexOutput/upserver/KVGameplayLoopTests/runs",Guid.NewGuid().ToString("N")));
|
||||
Directory.CreateDirectory(root);
|
||||
int assertions=0;
|
||||
void Check(bool yes,string why){assertions++;if(!yes)throw new Exception(why);}
|
||||
try {
|
||||
var type=Assembly.GetExecutingAssembly().GetType("game.PlayerDataStorage.PlayerKVLoopPermit");
|
||||
Check(type!=null,"Missing approved loop permit validation");
|
||||
object Load(string file)=>type.GetMethod("Read",BindingFlags.Static|BindingFlags.NonPublic).Invoke(null,new object[]{file});
|
||||
void Reject(string file,string why){bool bad=false;try{Load(file);}catch(TargetInvocationException e){bad=e.InnerException is InvalidOperationException;}Check(bad,why);}
|
||||
var backup=Path.Combine(root,"backup.json");File.WriteAllText(backup,JsonConvert.SerializeObject(new{playerId="101",api="http://s101.local:18080/",data=new Dictionary<string,string>{{"NewPlayerDataDic","{}"},{"k","v"}}}));
|
||||
var digest=Convert.ToHexString(SHA256.HashData(File.ReadAllBytes(backup)));
|
||||
var permit=Path.Combine(root,"permit.json");
|
||||
void Put(string id="101",string api="http://s101.local:18080/",string hash=null,string[] keys=null)=>File.WriteAllText(permit,JsonConvert.SerializeObject(new{Version=1,Enabled=true,PlayerId=id,Api=api,BackupPath=backup,BackupSha256=hash??digest,AllowedKeys=keys??new[]{"NewPlayerDataDic","k"}}));
|
||||
Put();var value=Load(permit);Check(value!=null,"valid explicit permit");
|
||||
Put(id:"102");Reject(permit,"backup account must match");
|
||||
Put(id:"103");Reject(permit,"outside user-selected accounts");
|
||||
Put(api:"http://elsewhere.invalid/");Reject(permit,"fixed formal API");
|
||||
Put(hash:new string('0',64));Reject(permit,"backup integrity");
|
||||
Put(keys:Array.Empty<string>());Reject(permit,"no empty permission");
|
||||
Put(keys:new[]{"k"});Reject(permit,"core whole-save permission required");
|
||||
Put(keys:new[]{"NewPlayerDataDic","new-unbacked-key"});Reject(permit,"no keys absent from backup without new reviewed fixture");
|
||||
Put(keys:new[]{"NewPlayerDataDic","NewPlayerDataDic"});Reject(permit,"duplicate key permission rejected");
|
||||
var originalBackup=File.ReadAllBytes(backup);
|
||||
File.WriteAllText(backup,JsonConvert.SerializeObject(new{playerId="101",api="http://s101.local:18080/",data=new Dictionary<string,string>()}));
|
||||
digest=Convert.ToHexString(SHA256.HashData(File.ReadAllBytes(backup)));
|
||||
Put(keys:new[]{"NewPlayerDataDic"});Reject(permit,"actual empty existing save cannot enable loop");
|
||||
File.WriteAllBytes(backup,originalBackup);digest=Convert.ToHexString(SHA256.HashData(originalBackup));
|
||||
Put();value=Load(permit);
|
||||
var claim=type.GetMethod("Claim",BindingFlags.Static|BindingFlags.NonPublic);
|
||||
string Claim(string instance)=>(string)claim.Invoke(null,new object[]{root,instance});
|
||||
var marker=Claim("process-1");Check(File.Exists(marker),"durable claim");
|
||||
bool denied=false;try{Claim("process-1");}catch(TargetInvocationException e){denied=e.InnerException is IOException;}Check(denied,"same process and reload rejected");
|
||||
Check(File.Exists(Claim("process-2")),"new process can claim");
|
||||
Check(File.Exists(marker),"old process mark retained");
|
||||
Console.WriteLine($"PASS permit-and-process-claim assertions={assertions} root={root}");return 0;
|
||||
}catch(Exception e){Console.WriteLine($"FAIL assertions={assertions} {e}");return 1;}
|
||||
Reference in New Issue
Block a user