Improve unit tests, cleanup

This commit is contained in:
Pascal Serrarens 2025-01-02 10:17:09 +01:00
parent 02920a56e2
commit 338936ace5
10 changed files with 89 additions and 352 deletions

View File

@ -9,7 +9,7 @@ namespace Passer.Control.Core {
this.networkId = networkId;
}
public ClientMsg(byte[] buffer) : base(buffer) {
public ClientMsg(byte[] buffer) {
this.networkId = buffer[1];
}
@ -19,57 +19,5 @@ namespace Passer.Control.Core {
buffer[ix++] = networkId;
return ClientMsg.length;
}
public override void Deserialize(byte[] buffer) {
base.Deserialize(buffer);
uint ix = 0;
networkId = buffer[ix];
}
public static async Task<bool> Receive(Stream dataStream, Participant client, byte packetSize) {
if (packetSize != length)
return false;
byte[] buffer = await Receive(dataStream, packetSize);
ClientMsg msg = new(buffer);
if (client.networkId == 0) {
// client.networkId = (byte)(Participant.clients.Count);
// NetworkIdMsg.Send(client, client.networkId);
client.messageQueue.Enqueue(msg);
}
else if (msg.networkId == 0) {
// NetworkIdMsg.Send(client, client.networkId);
client.messageQueue.Enqueue(msg);
}
return true;
}
public static byte Serialized(byte[] buffer, byte networkId) {
byte ix = 0;
buffer[ix++] = ClientMsg.Id;
buffer[ix++] = networkId;
return ix;
}
public static bool SendTo(Participant participant, byte networkId) {
if (participant == null)
return false;
byte ix = 0;
participant.buffer[ix++] = ClientMsg.Id;
participant.buffer[ix++] = networkId;
return participant.SendBuffer(ix);
}
public static bool Publish(Participant participant, byte networkId) {
if (participant == null)
return false;
byte ix = 0;
participant.buffer[ix++] = ClientMsg.Id;
participant.buffer[ix++] = networkId;
return participant.PublishBuffer(ix);
}
}
}

View File

@ -10,8 +10,8 @@
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit.Analyzers" Version="4.3.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
</ItemGroup>

View File

@ -17,7 +17,14 @@ namespace Passer.Control.Core {
this.thingId = thingId;
this.url = url;
}
public ModelUrlMsg(byte[] buffer) : base(buffer) { }
public ModelUrlMsg(byte[] buffer) {
byte ix = 1;
this.networkId = buffer[ix++];
this.thingId = buffer[ix++];
int strlen = buffer[ix++];
url = System.Text.Encoding.UTF8.GetString(buffer, (int)ix, strlen);
}
public override byte Serialize(ref byte[] buffer) {
byte ix = 0;
@ -30,54 +37,7 @@ namespace Passer.Control.Core {
buffer[ix++] = (byte)url[urlIx];
return ix;
}
public override void Deserialize(byte[] buffer) {
byte ix = 0;
this.networkId = buffer[ix++];
this.thingId = buffer[ix++];
int strlen = buffer[ix++];
url = System.Text.Encoding.UTF8.GetString(buffer, (int)ix, strlen);
}
public static bool Send(Participant client, Thing thing) {
if (string.IsNullOrEmpty(thing.modelUrl))
return true; // nothing sent, but still a success!
ModelUrlMsg msg = new(thing.networkId, thing.id, thing.modelUrl);
return SendMsg(client, msg);
}
public static bool Send(Participant client, byte networkId, byte thingId, string modelUrl) {
if (string.IsNullOrEmpty(modelUrl))
return true; // nothing sent, but still a success!
ModelUrlMsg msg = new(networkId, thingId, modelUrl);
return SendMsg(client, msg);
}
public static async Task<bool> Receive(Stream dataStream, Participant client, byte packetSize) {
byte[] buffer = await Receive(dataStream, packetSize);
ModelUrlMsg msg = new(buffer);
client.messageQueue.Enqueue(msg);
return true;
}
public static bool SendTo(Participant participant, Thing thing) {
if (participant == null || thing == null || thing.modelUrl == null)
return false;
byte urlLength = (byte)thing.modelUrl.Length;
if (participant.buffer.Length < 3 + urlLength)
return false;
byte ix = 0;
participant.buffer[ix++] = ModelUrlMsg.Id;
participant.buffer[ix++] = participant.networkId;
participant.buffer[ix++] = thing.id; // Thing Id
participant.buffer[ix++] = urlLength;
for (int urlIx = 0; urlIx < urlLength; urlIx++)
participant.buffer[ix++] = (byte)thing.modelUrl[urlIx];
return participant.SendBuffer(ix);
}
}
}

View File

@ -18,63 +18,28 @@ namespace Passer.Control.Core {
this.thingId = thingId;
this.name = name;
}
public NameMsg(byte[] buffer) : base(buffer) { }
public override byte Serialize(ref byte[] buffer) {
byte ix = 0;
buffer[ix++] = NameMsg.Id;
buffer[ix++] = this.networkId;
buffer[ix++] = this.thingId;
buffer[ix++] = (byte)this.name.Length;
for (int nameIx = 0; nameIx < this.name.Length; nameIx++)
buffer[ix++] = (byte)this.name[nameIx];
return ix;
}
public override void Deserialize(byte[] buffer) {
byte ix = 0;
public NameMsg(byte[] buffer) {
byte ix = 1;
this.networkId = buffer[ix++];
this.thingId = buffer[ix++];
int strlen = buffer[ix++];
this.name = System.Text.Encoding.UTF8.GetString(buffer, (int)ix, strlen);
}
public static bool Send(Participant client, Thing thing) {
if (string.IsNullOrEmpty(thing.name))
return true; // nothing sent, but still a success!
NameMsg msg = new(thing.networkId, thing.id, thing.name);
return SendMsg(client, msg);
}
//public static bool Send(Client client, byte networkId, byte thingId, string name)
//{
// NameMsg msg = new(networkId, thingId, name);
// return SendMsg(client, msg);
//}
public static async Task<bool> Receive(Stream dataStream, Participant client, byte packetSize) {
byte[] buffer = await Receive(dataStream, packetSize);
NameMsg msg = new(buffer);
client.messageQueue.Enqueue(msg);
return true;
}
public static bool SendTo(Participant participant, Thing thing) {
if (participant == null || thing == null || thing.name == null)
return false;
byte nameLength = (byte)thing.name.Length;
if (participant.buffer.Length < 3 + nameLength)
return false;
public override byte Serialize(ref byte[] buffer) {
byte ix = 0;
participant.buffer[ix++] = NameMsg.Id;
participant.buffer[ix++] = participant.networkId;
participant.buffer[ix++] = thing.id;
participant.buffer[ix++] = nameLength;
for (int nameIx = 0; nameIx < nameLength; nameIx++)
participant.buffer[ix++] = (byte)thing.name[nameIx];
buffer[ix++] = NameMsg.Id;
buffer[ix++] = this.networkId;
buffer[ix++] = this.thingId;
return participant.SendBuffer(ix);
int nameLength = 0;
if (this.name != null)
nameLength = this.name.Length;
buffer[ix++] = (byte)nameLength;
for (int nameIx = 0; nameIx < nameLength; nameIx++)
buffer[ix++] = (byte)this.name[nameIx];
return ix;
}
}

View File

@ -8,7 +8,7 @@ namespace Passer.Control.Core {
public NetworkIdMsg(byte networkId) {
this.networkId = networkId;
}
public NetworkIdMsg(byte[] buffer) : base(buffer) {
public NetworkIdMsg(byte[] buffer) {
this.networkId = buffer[1];
}
@ -17,36 +17,6 @@ namespace Passer.Control.Core {
buffer[1] = this.networkId;
return NetworkIdMsg.length;
}
public override void Deserialize(byte[] buffer) {
uint ix = 1;
this.networkId = buffer[ix];
}
public static bool Send(Participant client, byte networkId) {
NetworkIdMsg msg = new(networkId);
return SendMsg(client, msg);
}
public static async Task<bool> Receive(Stream dataStream, Participant client, byte packetSize) {
if (packetSize != length)
return false;
byte[] buffer = await Receive(dataStream, packetSize);
NetworkIdMsg msg = new(buffer);
client.messageQueue.Enqueue(msg);
return true;
}
public static bool SendTo(Participant participant, byte networkId) {
if (participant == null)
return false;
byte ix = 0;
participant.buffer[ix++] = NetworkIdMsg.Id;
participant.buffer[ix++] = networkId;
return participant.SendBuffer(ix);
}
}
}

View File

@ -14,7 +14,6 @@ namespace Passer.Control.Core {
public string ipAddress = "0.0.0.0";
public string broadcastIpAddress = "255.255.255.255";
public int port;
// public Stream dataStream;
public byte[] buffer = new byte[256];
@ -42,7 +41,6 @@ namespace Passer.Control.Core {
#region Init
public Participant() {
// this.dataStream = new EchoStream();
others.Add(this);
}
@ -63,7 +61,6 @@ namespace Passer.Control.Core {
public Participant(UdpClient udpClient, int port) : this() {
this.udpClient = udpClient;
this.port = port;
//this.dataStream = new EchoStream();
//clients.Add(this);
}
@ -71,27 +68,19 @@ namespace Passer.Control.Core {
#region Update
protected async void ReceiveUDP(IAsyncResult result) {
protected void ReceiveUDP(IAsyncResult result) {
if (udpClient == null || this.endPoint == null)
return;
try {
// Console.WriteLine($"{this.name} received");
byte[] data = udpClient.EndReceive(result, ref this.endPoint);
// This does not yet take multi-packet messages into account!
byte[] data = udpClient.EndReceive(result, ref this.endPoint);
// This does not yet take multi-packet messages into account!
Participant remoteParticipant = this.GetParticipant(endPoint.Address.ToString(), endPoint.Port);
if (remoteParticipant == null) {
remoteParticipant = this.AddParticipant(endPoint.Address.ToString(), endPoint.Port);
}
await ReceiveData(data, remoteParticipant);
// this.dataStream.WriteByte((byte)data.Length);
// this.dataStream.Write(data, 0, data.Length);
//Task task = Task.Run(() => ReceiveData());
}
catch (Exception _) {
Console.WriteLine("connection error");
Participant remoteParticipant = this.GetParticipant(endPoint.Address.ToString(), endPoint.Port);
if (remoteParticipant == null) {
remoteParticipant = this.AddParticipant(endPoint.Address.ToString(), endPoint.Port);
}
ReceiveData(data, remoteParticipant);
udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
}
@ -102,17 +91,17 @@ namespace Passer.Control.Core {
public virtual void Update(long currentTimeMs) {
if (currentTimeMs > this.nextPublishMe) {
this.Publish(new ClientMsg(this.networkId));
Console.WriteLine($"{this.name} Sent ClientMsg {this.networkId}");
// Console.WriteLine($"{this.name} Sent ClientMsg {this.networkId}");
this.nextPublishMe = currentTimeMs + Participant.publishInterval;
}
for (int ix = 0; ix < this.others.Count; ix++) {
Participant client = this.others[ix];
if (client == null)
continue;
// for (int ix = 0; ix < this.others.Count; ix++) {
// Participant client = this.others[ix];
// if (client == null)
// continue;
this.ProcessMessages(client);
}
// this.ProcessMessages(client);
// }
Thing.UpdateAll(currentTimeMs);
}
@ -121,6 +110,7 @@ namespace Passer.Control.Core {
#region Send
public void SendThingInfo(Thing thing) {
Console.WriteLine("Send thing info");
this.Send(new ThingMsg(this.networkId, thing));
this.Send(new NameMsg(this.networkId, thing));
this.Send(new ModelUrlMsg(this.networkId, thing));
@ -131,7 +121,7 @@ namespace Passer.Control.Core {
if (bufferSize <= 0)
return true;
Console.WriteLine($"msg to {endPoint.Address.ToString()} {endPoint.Port}");
// Console.WriteLine($"msg to {endPoint.Address.ToString()} {endPoint.Port}");
this.udpClient?.Send(this.buffer, bufferSize, this.endPoint);
return true;
}
@ -168,46 +158,31 @@ namespace Passer.Control.Core {
#region Receive
// public async Task ReceiveData_old() {
// while (true) {
// byte packetSize = (byte)this.dataStream.ReadByte();
// if (packetSize != 0xFF)
// await ReceiveData(this.dataStream, this, packetSize);
// // else timeout
// }
// }
// public static async Task ReceiveData(Stream dataStream, Participant client, byte packetSize) {
public async Task ReceiveData(byte[] data, Participant remoteParticipant) {
// byte msgId = (byte)dataStream.ReadByte();
public void ReceiveData(byte[] data, Participant remoteParticipant) {
byte msgId = data[0];
if (msgId == 0xFF) {
// Timeout
return;
}
// Console.WriteLine($"R {msgId} from {remoteParticipant.ipAddress}");
bool result = false;
switch (msgId) {
case ClientMsg.Id: // 0xA0 / 160
//result = await ClientMsg.Receive(dataStream, client, packetSize);
this.ProcessClientMsg(remoteParticipant, new ClientMsg(data));
this.Process(remoteParticipant, new ClientMsg(data));
break;
case NetworkIdMsg.Id: // 0xA1 / 161
//result = await NetworkIdMsg.Receive(dataStream, client, packetSize);
this.ProcessNetworkIdMsg(remoteParticipant, new NetworkIdMsg(data));
this.Process(remoteParticipant, new NetworkIdMsg(data));
break;
case InvestigateMsg.Id: // 0x81
// result = await InvestigateMsg.Receive(dataStream, client, packetSize);
break;
case ThingMsg.id: // 0x80 / 128
// result = await ThingMsg.Receive(dataStream, client, packetSize);
this.Process(new ThingMsg(data));
break;
case NameMsg.Id: // 0x91 / 145
// result = await NameMsg.Receive(dataStream, client, packetSize);
this.Process(new NameMsg(data));
break;
case ModelUrlMsg.Id: // 0x90 / 144
// result = await ModelUrlMsg.Receive(dataStream, client, packetSize);
this.Process(new ModelUrlMsg(data));
break;
case PoseMsg.Id: // 0x10 / 16
// result = await PoseMsg.Receive(dataStream, client, packetSize);
@ -224,82 +199,34 @@ namespace Passer.Control.Core {
default:
break;
}
// if (result == false) {
// packetSize = msgId; // skip 1 byte, msgId is possibly a packet size byte
// await ReceiveData(dataStream, client, packetSize);
// }
}
#endregion
#region Process
public virtual void ProcessMessages(Participant remoteParticipant) {
while (this.messageQueue.TryDequeue(out IMessage msg))
ProcessMessage(remoteParticipant, msg);
}
protected virtual void Process(Participant sender, ClientMsg msg) { }
public void ProcessMessage(Participant remoteParticipant, IMessage msg) {
switch (msg) {
case ClientMsg clientMsg:
ProcessClientMsg(remoteParticipant, clientMsg);
break;
case NetworkIdMsg networkId:
ProcessNetworkIdMsg(remoteParticipant, networkId);
break;
case InvestigateMsg investigate:
ProcessInvestigateMsg(investigate);
break;
case ThingMsg thing:
ProcessThingMsg(thing);
break;
case NameMsg name:
//UnityEngine.Debug.Log($"Name [{name.networkId}/{name.thingId}] {name.name}");
ProcessNameMsg(name);
break;
case ModelUrlMsg modelUrl:
ProcessModelUrlMsg(modelUrl);
break;
case PoseMsg pose:
ProcessPoseMsg(pose);
break;
case CustomMsg custom:
ProcessCustomMsg(custom);
break;
case TextMsg text:
ProcessTextMsg(text);
break;
case DestroyMsg destroy:
ProcessDestroyMsg(destroy);
break;
default:
return;
}
ForwardMessage(msg);
}
protected virtual void ProcessClientMsg(Participant sender, ClientMsg msg) { }
protected virtual void ProcessNetworkIdMsg(Participant sender, NetworkIdMsg msg) {
protected virtual void Process(Participant sender, NetworkIdMsg msg) {
Console.WriteLine($"{this.name} receive network id {this.networkId} {msg.networkId}");
if (this.networkId != msg.networkId) {
this.networkId = msg.networkId;
foreach (Thing thing in Thing.GetAllThings())
this.SendThingInfo(thing);
sender.SendThingInfo(thing);
}
}
protected virtual void ProcessInvestigateMsg(InvestigateMsg msg) { }
protected virtual void Process(InvestigateMsg msg) { }
protected virtual void ProcessThingMsg(ThingMsg msg) {
protected virtual void Process(ThingMsg msg) {
Console.WriteLine($"received thing {msg.thingId}");
}
protected virtual void ProcessNameMsg(NameMsg msg) {
protected virtual void Process(NameMsg msg) {
Console.WriteLine($"received name {msg.name}");
}
protected virtual void ProcessModelUrlMsg(ModelUrlMsg msg) {
protected virtual void Process(ModelUrlMsg msg) {
Console.WriteLine($"received name {msg.url}");
}

View File

@ -5,7 +5,7 @@ namespace Passer.Control.Core {
public class SiteServer : Participant {
public SiteServer(int port) {
public SiteServer(int port = 7681) {
this.ipAddress = "0.0.0.0";
this.port = port;
this.endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), 0); // for sending, but should not be used really...
@ -16,21 +16,24 @@ namespace Passer.Control.Core {
}
public override void Update(long currentTimeMs) {
for (int ix = 0; ix < this.others.Count; ix++) {
Participant client = this.others[ix];
if (client == null)
continue;
// for (int ix = 0; ix < this.others.Count; ix++) {
// Participant client = this.others[ix];
// if (client == null)
// continue;
this.ProcessMessages(client);
}
// this.ProcessMessages(client);
// }
Thing.UpdateAll(currentTimeMs);
}
protected override void ProcessClientMsg(Participant sender, ClientMsg msg) {
protected override void Process(Participant sender, ClientMsg msg) {
if (msg.networkId == 0) {
Console.WriteLine($"{this.name} received New Client -> {sender.networkId}");
sender.Send(new NetworkIdMsg(sender.networkId));
}
}
protected override void Process(Participant sender, NetworkIdMsg msg) {
}
}
}

View File

@ -12,7 +12,10 @@ namespace Passer.Control.Core {
this.networkId = networkId;
this.thingId = thing.id;
this.thingType = thing.type;
this.parentId = thing.parent.id;
if (thing.parent != null)
this.parentId = thing.parent.id;
else
this.parentId = 0;
}
public ThingMsg(byte networkId, byte thingId, byte thingType, byte parentId) {
this.networkId = networkId;
@ -20,7 +23,13 @@ namespace Passer.Control.Core {
this.thingType = thingType;
this.parentId = parentId;
}
public ThingMsg(byte[] buffer) : base(buffer) { }
public ThingMsg(byte[] buffer) {
uint ix = 0;
this.networkId = buffer[ix++];
this.thingId = buffer[ix++];
this.thingType = buffer[ix++];
this.parentId = buffer[ix];
}
public override byte Serialize(ref byte[] buffer) {
byte ix = 0;
@ -31,56 +40,6 @@ namespace Passer.Control.Core {
buffer[ix++] = this.parentId;
return ThingMsg.length;
}
public override void Deserialize(byte[] buffer) {
uint ix = 0;
this.networkId = buffer[ix++];
this.thingId = buffer[ix++];
this.thingType = buffer[ix++];
this.parentId = buffer[ix];
}
public static bool Send(Participant client, Thing thing) {
ThingMsg msg = new(thing.networkId, thing.id, thing.type, thing.parent.id);
return SendMsg(client, msg);
}
//public static bool Send(Client client, byte networkId, byte thingId, byte thingType, byte parentId)
//{
// ThingMsg msg = new(networkId, thingId, thingType, parentId);
// //UnityEngine.Debug.Log($"Send thing [{msg.networkId}/{msg.thingId}]");
// return SendMsg(client, msg);
//}
public static async Task<bool> Receive(Stream dataStream, Participant client, byte packetSize) {
if (packetSize != length)
return false;
byte[] buffer = await Receive(dataStream, packetSize);
ThingMsg msg = new(buffer);
//UnityEngine.Debug.Log($"Receive thing [{msg.networkId}/{msg.thingId}]");
// Do no process poses with nwid == 0 (== local)
//if (msg.networkId == 0)
// return true;
client.messageQueue.Enqueue(msg);
return true;
}
public static bool SendTo(Participant participant, Thing thing) {
if (participant == null || thing == null)
return false;
byte ix = 0;
participant.buffer[ix++] = ThingMsg.id;
participant.buffer[ix++] = participant.networkId;
participant.buffer[ix++] = thing.id;
participant.buffer[ix++] = thing.type;
if (thing.parent != null)
participant.buffer[ix++] = thing.parent.id;
else
participant.buffer[ix++] = 0;
return participant.SendBuffer(ix);
}
}
}

View File

@ -1,7 +1,10 @@
namespace test;
using System;
using NUnit.Framework;
using Passer.Control.Core;
namespace ControlCore.test;
public class Tests {
[SetUp]
public void Setup() {
@ -46,7 +49,7 @@ public class Tests {
long milliseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
long startTime = milliseconds;
while (milliseconds < startTime + 7000) {
while (milliseconds < startTime + 1000) {
siteServer.Update(milliseconds);
participant.Update(milliseconds);
@ -54,11 +57,12 @@ public class Tests {
milliseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
Assert.Pass();
Assert.That(participant.networkId, Is.EqualTo(1));
}
[Test]
public void Test_ThingMsg() {
SiteServer siteServer = new();
Participant participant = new("127.0.0.1");
Thing thing = new() {
name = "First Thing",
@ -68,12 +72,13 @@ public class Tests {
long milliseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
long startTime = milliseconds;
while (milliseconds < startTime + 7000) {
siteServer.Update(milliseconds);
participant.Update(milliseconds);
Thread.Sleep(100);
milliseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
Assert.Pass();
Assert.That(participant.networkId, Is.EqualTo(1));
}
}

View File

@ -11,8 +11,8 @@
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit.Analyzers" Version="4.3.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
</ItemGroup>