79 lines
5.5 KiB
Python
79 lines
5.5 KiB
Python
"""Production map-response validation and delayed delivery, with engine JSON/UI doubled."""
|
|
from policy_harness import ROOT, body, run
|
|
|
|
base = ROOT/'addons/core/Scripts/Game/ERR/00_Core'
|
|
p = base/'ERR_CommunityStatistics.c'
|
|
valid = body(p, 'bool Valid(')
|
|
matches = body(p, 'bool Matches(').replace('server.', 'server->').replace('allServers.', 'allServers->')
|
|
callbacks = '\n'.join(body(base/'ERR_Telemetry.c', name) for name in ['protected void CommunityUnavailable(', 'protected void UpdateCommunity('])
|
|
for a,b in [
|
|
('protected ', ''), ('RestCallback callback','RestCallback* callback'), ('callback.', 'callback->'),
|
|
('JsonLoadContext sent = new JsonLoadContext()', 'Json sent'), ('JsonLoadContext reply = new JsonLoadContext()', 'Json reply'),
|
|
('ERR_CommunityStatistics community;', 'Community* community = nullptr;'), ('community.', 'community->'),
|
|
('m_Mode.ERR_PublishCommunityStatistics(', 'mode.Publish('), ('m_State.serverId','serverId'),
|
|
('GetGame().GetWorldFile()', 'world'),
|
|
]: callbacks=callbacks.replace(a,b)
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <string>
|
|
struct string:std::string {using std::string::string;using std::string::operator=;bool IsEmpty()const{return empty();}int Length()const{return size();}};
|
|
struct Record {int wins=2,losses=1,completed=3,partialMissions=0;
|
|
'''+valid+r'''
|
|
};
|
|
struct Community {int schemaVersion=1;string serverId="server",missionId="mission",eventId="final",terrain="map",outcome="victory";Record local,global;Record* server=&local;Record* allServers=&global;
|
|
'''+matches+r'''
|
|
string Summary(){return "map record";}
|
|
} result;
|
|
struct Json {
|
|
string input;
|
|
bool LoadFromString(string v){input=v;return v=="old"||v=="final"||v=="response";}
|
|
bool ReadValue(string,string& value){value=input;return true;}
|
|
bool ReadValue(string,Community*& value){value=&result;return true;}
|
|
};
|
|
struct RestCallback {string data="response";string GetData(){return data;}};
|
|
struct Service {
|
|
bool m_Ended=true,current=true,m_CommunityReady=false;string m_FinalEventId="final",m_FinalOutcome="victory",m_InFlight="final",serverId="server",m_MissionId="mission",world="map";
|
|
struct Mode {int writes=0;string text;void Publish(string v){writes++;text=v;}} mode;
|
|
bool Current(){return current;}
|
|
'''+callbacks+r'''
|
|
};
|
|
int main(){
|
|
assert(result.Matches("server","mission","final","map","victory"));
|
|
assert(!result.Matches("other","mission","final","map","victory"));
|
|
assert(!result.Matches("server","old","final","map","victory"));
|
|
assert(!result.Matches("server","mission","old-event","map","victory"));
|
|
assert(!result.Matches("server","mission","final","another-map","victory"));
|
|
assert(!result.Matches("server","mission","final","map","defeat"));
|
|
result.schemaVersion=2;assert(!result.Matches("server","mission","final","map","victory"));result.schemaVersion=1;
|
|
result.global.wins=1;result.global.completed=2;assert(!result.Matches("server","mission","final","map","victory"));result.global=Record{};
|
|
result.local.wins=-1;assert(!result.local.Valid());result.local=Record{};
|
|
result.local.completed=4;assert(!result.local.Valid());result.local=Record{};
|
|
result.local.partialMissions=4;assert(!result.local.Valid());result.local=Record{};
|
|
Service service;RestCallback cb;
|
|
service.m_InFlight="old";service.UpdateCommunity(&cb);assert(service.mode.writes==0);
|
|
service.m_InFlight="final";service.current=false;service.UpdateCommunity(&cb);assert(service.mode.writes==0);
|
|
service.current=true;service.m_Ended=false;service.UpdateCommunity(&cb);assert(service.mode.writes==0);
|
|
service.m_Ended=true;service.UpdateCommunity(&cb);assert(service.mode.text=="map record");
|
|
int receivedWrites=service.mode.writes;service.CommunityUnavailable();assert(service.mode.writes==receivedWrites); // an older queued upload failing cannot erase confirmed totals
|
|
service.m_CommunityReady=false;
|
|
result.terrain="other-map";service.UpdateCommunity(&cb);assert(service.mode.text.find("unavailable")!=std::string::npos);result.terrain="map";
|
|
service.UpdateCommunity(&cb);assert(service.mode.text=="map record"); // later valid retry refreshes the fallback
|
|
service.m_CommunityReady=false;
|
|
cb.data="invalid-json";service.UpdateCommunity(&cb);assert(service.mode.text.find("unavailable")!=std::string::npos);
|
|
cb.data=string(8193,'x');service.UpdateCommunity(&cb);assert(service.mode.text.find("unavailable")!=std::string::npos);
|
|
cb.data="response";service.m_FinalOutcome="interrupted";int before=service.mode.writes;service.UpdateCommunity(&cb);assert(service.mode.writes==before);
|
|
service.m_FinalOutcome="defeat";result.outcome="defeat";service.UpdateCommunity(&cb);assert(service.mode.text=="map record");
|
|
service.m_CommunityReady=false;
|
|
result.local.losses=0;result.local.completed=2;service.UpdateCommunity(&cb);assert(service.mode.text.find("unavailable")!=std::string::npos);
|
|
}
|
|
''')
|
|
mode=(base/'ERR_RoundStatisticsLifecycle.c').read_text()
|
|
assert '[RplProp(onRplName: "ERR_OnRoundStatisticsReplicated")]\n protected string m_ERRCommunitySummary' in mode
|
|
publish=body(base/'ERR_RoundStatisticsLifecycle.c','void ERR_PublishCommunityStatistics(')
|
|
assert '!Replication.IsServer()' in publish and 'Replication.BumpMe(); ERR_OnRoundStatisticsReplicated();' in publish
|
|
assert 'm_ERRCommunitySummary + "\\n\\n" + m_ERRRoundSummary' in mode
|
|
sender=(base/'ERR_Telemetry.c').read_text()
|
|
assert 'm_State.pending.InsertAt(payload, 0);' in sender
|
|
assert 'GetGame().GetCallqueue().CallLater(Pulse, 1, false)' in sender
|
|
print('PASS: map/server/mission/event/outcome validation, bounded counters, stale delivery exclusion, current-round refresh and unavailable recovery')
|