#--------------------------------------------------------------------------- # # Title : EMESARY tests # # File Type : Unit test # # Author : Richard Harrison (richard@zaretto.com) # # Creation Date : 14 June 2020 # # Copyright (C) 2020 Richard Harrison Released under GPL V2 # #---------------------------------------------------------------------------*/ # fgcommand("nasal-test", props.Node.new({"path":"test_emesary.nut"})); # note you can omit this if not needed var setUp = func { logprint(LOG_INFO, "Emesary tests begin"); }; # same, cab be ommitted var tearDown = func { logprint(LOG_INFO, "Emesary tests finished"); }; var test_emesary_transmit_receive = func { logprint(LOG_INFO, "Emesary test transmit receive"); var baseRecipientCount = emesary.GlobalTransmitter.RecipientCount(); logprint(LOG_INFO, " (notice) already have ",baseRecipientCount); var TestFailCount = 0; var TestSuccessCount = 0; var TestNotification = { new: func(_value) { var new_class = emesary.Notification.new("TestNotification", _value); return new_class; }, }; var TestNotProcessedNotification = { new: func(_value) { var new_class = emesary.Notification.new("TestNotProcessedNotification", _value); return new_class; }, }; var RadarReturnNotification = { new: func(_value, _x, _y, _z) { var new_class = emesary.Notification.new("RadarReturnNotification", _value); new_class.x = _x; new_class.y = _y; new_class.z = _z; return new_class; }, }; var TestRecipient = { new: func(_ident) { var new_class = emesary.Recipient.new(_ident); new_class.count = 0; new_class.Receive = func(notification) { if (notification.NotificationType == "TestNotification") { me.count = me.count + 1; return emesary.Transmitter.ReceiptStatus_OK; } return emesary.Transmitter.ReceiptStatus_NotProcessed; }; return new_class; }, }; var TestRadarRecipient = { new: func(_ident) { var new_class = emesary.Recipient.new(_ident); new_class.Value = ""; new_class.Receive = func(notification) { if (notification.NotificationType == "RadarReturnNotification"){ new_class.ReturnValue = sprintf("%s:%s.%s.%s",notification.NotificationType, notification.x, notification.y, notification.z); notification.ReturnValue = new_class; return emesary.Transmitter.ReceiptStatus_OK; } return emesary.Transmitter.ReceiptStatus_NotProcessed; }; return new_class; }, }; var PerformTest = func(tid, expected_value, method) { var testResult = method(); if (testResult) { TestSuccessCount = TestSuccessCount + 1; logprint(LOG_INFO, sprintf(" %s [Pass] :%s == %s",tid,expected_value, testResult)); } else { TestFailCount = TestFailCount + 1; logprint(LOG_ALERT, sprintf(" %s [Fail] : %s != %s",tid,expected_value, testResult)); } unitTest.assert(expected_value, testResult, tid); } var tt = TestRecipient.new("tt recipient"); var tt1 = TestRecipient.new("tt1 recipient1"); var tt3 = TestRecipient.new("tt3 recipient3"); var tt_radar_recipient = TestRadarRecipient.new("tt_radar_recipient: Radar Test recipient2"); PerformTest("Create Notification", "TestNotification.Test notification", func { var tn = TestNotification.new("Test notification"); return tn.NotificationType~"."~tn.Ident; }); PerformTest("Register tt", 1 + baseRecipientCount, func { emesary.GlobalTransmitter.Register(tt); return emesary.GlobalTransmitter.RecipientCount(); }); PerformTest("Register tt1", 2 + baseRecipientCount, func { emesary.GlobalTransmitter.Register(tt1); return emesary.GlobalTransmitter.RecipientCount(); }); PerformTest("Register tt_radar_recipient", 3 + baseRecipientCount, func { emesary.GlobalTransmitter.Register(tt_radar_recipient); return emesary.GlobalTransmitter.RecipientCount(); }); PerformTest("Register tt3", 4 + baseRecipientCount, func { emesary.GlobalTransmitter.Register(tt3); return emesary.GlobalTransmitter.RecipientCount(); }); PerformTest("Notify", 1, func { var rv = emesary.GlobalTransmitter.NotifyAll(TestNotification.new("Test notification")); return !emesary.Transmitter.IsFailed(rv) and rv != emesary.Transmitter.ReceiptStatus_NotProcessed and tt.count == 1; }); PerformTest("DeRegister tt1", 3 + baseRecipientCount, func { emesary.GlobalTransmitter.DeRegister(tt1); return emesary.GlobalTransmitter.RecipientCount(); }); # tt1_count = tt1.count; PerformTest("NotifyAfterDeregister", tt1.count, func { emesary.GlobalTransmitter.NotifyAll(TestNotification.new("Test notification")); # return tt1.count == tt1_count; return tt1.count; }); tt.count = 0; PerformTest("Recipient.Active", 1, func { var rv = emesary.GlobalTransmitter.NotifyAll(TestNotification.new("Test notification")); if (!emesary.Transmitter.IsFailed(rv) and rv != emesary.Transmitter.ReceiptStatus_NotProcessed) return tt.count; else return -1000; }); PerformTest("Test Not Processed Notification", emesary.Transmitter.ReceiptStatus_NotProcessed, func { var rv = emesary.GlobalTransmitter.NotifyAll(TestNotProcessedNotification.new("Not Processed")); return rv; }); PerformTest("NotifyAll", "RadarReturnNotification.x0.y0.z0", func { emesary.GlobalTransmitter.NotifyAll(RadarReturnNotification.new("Radar notification", "x0","y0","z0")); return tt_radar_recipient.ReturnValue; }); PerformTest("Deregister", 0 + baseRecipientCount, func { emesary.GlobalTransmitter.DeRegister(tt); emesary.GlobalTransmitter.DeRegister(tt3); emesary.GlobalTransmitter.DeRegister(tt_radar_recipient); return emesary.GlobalTransmitter.RecipientCount(); }); } #---1 # all test macros take an option 'message' argument test_transfer = func { logprint(LOG_INFO, "Emesary: Test_transfers"); var decoded = 10; var coded = "1234"; var init = 1; var counter = 11; var pos = 4; while (init or (size(coded) == 4 and pos == 4 and decoded == counter-1 and find(emesary_mp_bridge.OutgoingMPBridge.MessageEndChar,coded) == -1 and find(emesary_mp_bridge.OutgoingMPBridge.SeperatorChar,coded) == -1 and counter != 65600)) { coded = emesary.BinaryAsciiTransfer.encodeInt(counter,4); if (init) { init = 0; } decoded = emesary.BinaryAsciiTransfer.decodeInt(coded,4,0); pos = decoded.pos; decoded = decoded.value; counter += 1; } unitTest.assert_equal(counter, 65600, sprintf("Decoded=%d Coded=%s Integer=%d Pos=%d Size=%d", decoded, coded, counter-1, pos, size(coded))); for(i=-1;i<=1;i+=0.1){ var dv = emesary.TransferNorm.encode(i,2); var v = emesary.TransferNorm.decode(dv, 2,0); var delta = math.abs(i - v.value); unitTest.assert(delta <= 0.01, sprintf("Norm: Fail: %f => %f : d=%f",i,v.value,delta)); } for(i=-124;i<124;i+=1){ var dv = emesary.TransferByte.encode(i); var v = emesary.TransferByte.decode(dv, 0); unitTest.assert(i == v.value, sprintf("Byte: fail: %d => %d ",i,v.value)); } var pos = 0; var v = emesary.BinaryAsciiTransfer.encodeNumeric(123, 1, 1.0); var dv=emesary.BinaryAsciiTransfer.decodeNumeric(v,1,1.0 ,pos); unitTest.assert_equal(dv.value,123, "BinaryAsciiTransfer.encodeNumeric"); for(i=-123; i <= 123; i+=1){ var v = emesary.BinaryAsciiTransfer.encodeNumeric(i,1, 1.0); var pos = 0; var dv=emesary.BinaryAsciiTransfer.decodeNumeric(v,1,1.0 ,pos); unitTest.assert_equal(dv.value, i, "BinaryAsciiTransfer.encodeNumeric(1)"); } teststring = func(s){ dv = emesary.TransferString.encode(s); nv = emesary.TransferString.decode(dv,0); unitTest.assert_equal(s, nv.value, "emesary.TransferString"); } teststring(""); teststring("@"); teststring("--"); teststring("qqqqqqqqqq-"); } test_mp_bridge = func { logprint(LOG_INFO,"Emesary MP bridge tests start"); var testMpPropertyPath = "/ai[0]/models[0]/multiplayer[11]"; var mp_listener = nil; var testRoutedNotifications = [notifications.GeoEventNotification.new(nil)]; var testBridgedTransmitter = emesary.Transmitter.new("geoOutgoingBridge"); var testOutgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("F-14mp.geo",testRoutedNotifications, 18, "", testBridgedTransmitter); testOutgoingBridge.MPStringMaxLen = 150; var msgList = []; var testRecipient = emesary.Recipient.new("Test"); valuesWithinRange = func(value1, value2, range){ return math.abs(value1 - value2) <= range; } testRecipient.FailCount = 0; testRecipient.Receive = func(notification) { if (notification.NotificationType == "GeoEventNotification") { # print ("recv(0): type=",notification.NotificationType, " fromIncoming=",notification.FromIncomingBridge); if (notification.Name=="DONE") { printf("Emesary MP Bridge tests completed; %d failure",me.FailCount); # now clean up; emesary.GlobalTransmitter.DeRegister(testRecipient); setprop("/ai/models/model-removed",testMpPropertyPath); if (mp_listener != nil) removelistener(mp_listener); return emesary.Transmitter.ReceiptStatus_NotProcessed; # we're not processing it, just looking } foreach (var msg; msgList) { if (msg.SecondaryKind == notification.SecondaryKind) { #print("Check msg ",msg.Kind); var failed = 0; if (math.abs(msg.Position.lat() - notification.Position.lat()) > 0.00001 or math.abs(msg.Position.lon() - notification.Position.lon()) > 0.00001 or math.abs(msg.Position.alt() - notification.Position.alt()) > 1) { failed = 1; printf("Fail Position:(%d) %s != %s",msg.Kind, msg.Position, notification.Position); } if (msg.Name != notification.Name) { failed = 1; printf("Fail Name:(%d) %s != %s",msg.Kind, msg.Name, notification.Name); } if (msg.Kind != notification.Kind) { failed = 1; printf("Fail Kind:(%d) %s != %s",msg.Kind, msg.Kind, notification.Kind); } if (msg.SecondaryKind != notification.SecondaryKind) { failed = 1; printf("Fail SecondaryKind:(%d) %s != %s",msg.Kind, msg.SecondaryKind, notification.SecondaryKind); } if (!valuesWithinRange(msg.u_fps, notification.u_fps,1)) { failed = 1; printf("Fail u_fps:(%d) %s != %s",msg.Kind, msg.u_fps, notification.u_fps); } if (!valuesWithinRange(msg.v_fps, notification.v_fps,1)) { failed = 1; printf("Fail v_fps:(%d) %s != %s",msg.Kind, msg.v_fps, notification.v_fps); } if (!valuesWithinRange(msg.w_fps, notification.w_fps,1)) { failed = 1; printf("Fail w_fps:(%d) %s != %s",msg.Kind, msg.w_fps, notification.w_fps); } if (msg.RemoteCallsign != notification.RemoteCallsign) { failed = 1; printf("Fail RemoteCallsign:(%d) %s != %s",msg.Kind, msg.RemoteCallsign, notification.RemoteCallsign); } if (msg.Flags != notification.Flags) { failed = 1; printf("Fail Flags:(%d) %s != %s",msg.Kind, msg.Flags, notification.Flags); } if (!failed) printf("%s (%d) received correctly",notification.NotificationType, notification.Kind); else me.FailCount = me.FailCount + 1; return emesary.Transmitter.ReceiptStatus_NotProcessed; # we're not processing it, just looking } } print("Failed to locate notification Key=",msg.SecondaryKind); # debug.dump(notification); } return emesary.Transmitter.ReceiptStatus_NotProcessed; # we're not processing it, just looking } # register the test recipient on the global transmitter as that is where messages will be bridged to emesary.GlobalTransmitter.Register(testRecipient); # start the incoming bridge - which will connect from the remote bridge (testBridgedTransmitter) # and route the notifications so that they come out of the global transmitter. emesary_mp_bridge.IncomingMPBridge.startMPBridge(testRoutedNotifications, 18, emesary.GlobalTransmitter); # # Create the incoming bridge by faking a model appearing # var node = props.getNode(testMpPropertyPath,1); node.getNode("callsign",1).setValue("test-mp"); var mpNode = node.getNode("sim/multiplay",1); bridgeNode = mpNode.getNode("emesary/bridge[18]",1); # # lastly we need to manually copy the properties from where the outgoing bridge puts them # to where the incoming bridge expects them. # This is normally performed by the multiplayer code - but for test purposes this # allows testing on a single instance. mp_listener = setlistener("/sim/multiplay/emesary/bridge[18]", func(v){ bridgeNode.setValue(v.getValue()); },0,0); # This is what causes the incoming bridge to create a connection between the multiplayer node # and will result in an active incoming bridge setprop("/ai/models/model-added", testMpPropertyPath); # # send out test messages for (var idx=0; idx < 20; idx += 1) { var msg = notifications.GeoEventNotification.new("mhit", "AIM"~idx, 19, idx); testBridgedTransmitter.NotifyAll(msg); append(msgList, msg); } msg = notifications.GeoEventNotification.new("mhit", "DONE", 19, 100); testBridgedTransmitter.NotifyAll(msg); }