using System; using System.Threading.Tasks; using ZB.MOM.WW.MxGateway.Contracts.Proto; using ZB.MOM.WW.MxGateway.Worker.MxAccess; using ZB.MOM.WW.MxGateway.Worker.Sta; using ZB.MOM.WW.MxGateway.Worker.Tests.TestSupport; namespace ZB.MOM.WW.MxGateway.Worker.Tests.MxAccess; public sealed class MxAccessLiveComCreationTests { private const string LiveClientName = "ZB.MOM.WW.MxGateway.Worker.Tests"; private const string DefaultLiveAddItemReference = "TestChildObject.TestInt"; private const string DefaultLiveAddItem2Definition = "TestInt"; private const string DefaultLiveAddItem2Context = "TestChildObject"; /// Verifies that StartAsync creates the installed MXAccess COM object on the STA thread when opted in. /// A task that represents the asynchronous operation. [LiveMxAccessFact] public async Task StartAsync_WhenOptedIn_CreatesInstalledMxAccessComObjectOnSta() { using MxAccessStaSession session = new(); await session.StartAsync(workerProcessId: 1234); } /// Verifies that Register and Unregister round-trip server handles with installed MXAccess. /// A task that represents the asynchronous operation. [LiveMxAccessFact] public async Task RegisterAndUnregister_WhenOptedIn_RoundTripsInstalledMxAccessServerHandle() { using MxAccessStaSession session = new(); await session.StartAsync(workerProcessId: 1234); MxCommandReply registerReply = await session.DispatchAsync(new StaCommand( "session-1", "live-register", new MxCommand { Kind = MxCommandKind.Register, Register = new RegisterCommand { ClientName = LiveClientName, }, })); Assert.Equal(ProtocolStatusCode.Ok, registerReply.ProtocolStatus.Code); Assert.True(registerReply.Register.ServerHandle > 0); MxCommandReply unregisterReply = await session.DispatchAsync(new StaCommand( "session-1", "live-unregister", new MxCommand { Kind = MxCommandKind.Unregister, Unregister = new UnregisterCommand { ServerHandle = registerReply.Register.ServerHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, unregisterReply.ProtocolStatus.Code); } /// Verifies that AddItem and RemoveItem round-trip item handles with installed MXAccess. /// A task that represents the asynchronous operation. [LiveMxAccessFact] public async Task AddItemAndRemoveItem_WhenOptedIn_RoundTripsInstalledMxAccessItemHandle() { using MxAccessStaSession session = new(); await session.StartAsync(workerProcessId: 1234); MxCommandReply registerReply = await RegisterLiveSessionAsync(session, "live-add-register"); int serverHandle = registerReply.Register.ServerHandle; int itemHandle = 0; try { MxCommandReply addItemReply = await session.DispatchAsync(new StaCommand( "session-1", "live-add-item", new MxCommand { Kind = MxCommandKind.AddItem, AddItem = new AddItemCommand { ServerHandle = serverHandle, ItemDefinition = GetLiveAddItemReference(), }, })); Assert.Equal(ProtocolStatusCode.Ok, addItemReply.ProtocolStatus.Code); Assert.True(addItemReply.AddItem.ItemHandle > 0); itemHandle = addItemReply.AddItem.ItemHandle; MxCommandReply removeItemReply = await session.DispatchAsync(new StaCommand( "session-1", "live-remove-item", new MxCommand { Kind = MxCommandKind.RemoveItem, RemoveItem = new RemoveItemCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, removeItemReply.ProtocolStatus.Code); itemHandle = 0; } finally { if (itemHandle > 0) { await session.DispatchAsync(new StaCommand( "session-1", "live-remove-item-cleanup", new MxCommand { Kind = MxCommandKind.RemoveItem, RemoveItem = new RemoveItemCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); } await UnregisterLiveSessionAsync(session, serverHandle, "live-add-unregister"); } } /// Verifies that AddItem2 and RemoveItem preserve item context with installed MXAccess. /// A task that represents the asynchronous operation. [LiveMxAccessFact] public async Task AddItem2AndRemoveItem_WhenOptedIn_PreservesContextForInstalledMxAccess() { using MxAccessStaSession session = new(); await session.StartAsync(workerProcessId: 1234); MxCommandReply registerReply = await RegisterLiveSessionAsync(session, "live-add2-register"); int serverHandle = registerReply.Register.ServerHandle; int itemHandle = 0; try { MxCommandReply addItem2Reply = await session.DispatchAsync(new StaCommand( "session-1", "live-add-item2", new MxCommand { Kind = MxCommandKind.AddItem2, AddItem2 = new AddItem2Command { ServerHandle = serverHandle, ItemDefinition = DefaultLiveAddItem2Definition, ItemContext = DefaultLiveAddItem2Context, }, })); Assert.Equal(ProtocolStatusCode.Ok, addItem2Reply.ProtocolStatus.Code); Assert.True(addItem2Reply.AddItem2.ItemHandle > 0); itemHandle = addItem2Reply.AddItem2.ItemHandle; MxCommandReply removeItemReply = await session.DispatchAsync(new StaCommand( "session-1", "live-remove-item2", new MxCommand { Kind = MxCommandKind.RemoveItem, RemoveItem = new RemoveItemCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, removeItemReply.ProtocolStatus.Code); itemHandle = 0; } finally { if (itemHandle > 0) { await session.DispatchAsync(new StaCommand( "session-1", "live-remove-item2-cleanup", new MxCommand { Kind = MxCommandKind.RemoveItem, RemoveItem = new RemoveItemCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); } await UnregisterLiveSessionAsync(session, serverHandle, "live-add2-unregister"); } } /// Verifies that Advise and UnAdvise round-trip subscriptions with installed MXAccess. /// A task that represents the asynchronous operation. [LiveMxAccessFact] public async Task AdviseAndUnAdvise_WhenOptedIn_RoundTripsInstalledMxAccessSubscription() { using MxAccessStaSession session = new(); await session.StartAsync(workerProcessId: 1234); MxCommandReply registerReply = await RegisterLiveSessionAsync(session, "live-advise-register"); int serverHandle = registerReply.Register.ServerHandle; int itemHandle = 0; bool advised = false; try { MxCommandReply addItemReply = await session.DispatchAsync(new StaCommand( "session-1", "live-advise-add-item", new MxCommand { Kind = MxCommandKind.AddItem, AddItem = new AddItemCommand { ServerHandle = serverHandle, ItemDefinition = GetLiveAddItemReference(), }, })); Assert.Equal(ProtocolStatusCode.Ok, addItemReply.ProtocolStatus.Code); Assert.True(addItemReply.AddItem.ItemHandle > 0); itemHandle = addItemReply.AddItem.ItemHandle; MxCommandReply adviseReply = await session.DispatchAsync(new StaCommand( "session-1", "live-advise", new MxCommand { Kind = MxCommandKind.Advise, Advise = new AdviseCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, adviseReply.ProtocolStatus.Code); advised = true; MxCommandReply unAdviseReply = await session.DispatchAsync(new StaCommand( "session-1", "live-unadvise", new MxCommand { Kind = MxCommandKind.UnAdvise, UnAdvise = new UnAdviseCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, unAdviseReply.ProtocolStatus.Code); advised = false; MxCommandReply removeItemReply = await session.DispatchAsync(new StaCommand( "session-1", "live-advise-remove-item", new MxCommand { Kind = MxCommandKind.RemoveItem, RemoveItem = new RemoveItemCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, removeItemReply.ProtocolStatus.Code); itemHandle = 0; } finally { if (advised && itemHandle > 0) { await session.DispatchAsync(new StaCommand( "session-1", "live-unadvise-cleanup", new MxCommand { Kind = MxCommandKind.UnAdvise, UnAdvise = new UnAdviseCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); } if (itemHandle > 0) { await session.DispatchAsync(new StaCommand( "session-1", "live-advise-remove-item-cleanup", new MxCommand { Kind = MxCommandKind.RemoveItem, RemoveItem = new RemoveItemCommand { ServerHandle = serverHandle, ItemHandle = itemHandle, }, })); } await UnregisterLiveSessionAsync(session, serverHandle, "live-advise-unregister"); } } private static string GetLiveAddItemReference() { string itemReference = Environment.GetEnvironmentVariable("MXGATEWAY_LIVE_MXACCESS_ITEM"); return string.IsNullOrWhiteSpace(itemReference) ? DefaultLiveAddItemReference : itemReference; } private static async Task RegisterLiveSessionAsync( MxAccessStaSession session, string correlationId) { MxCommandReply reply = await session.DispatchAsync(new StaCommand( "session-1", correlationId, new MxCommand { Kind = MxCommandKind.Register, Register = new RegisterCommand { ClientName = LiveClientName, }, })); Assert.Equal(ProtocolStatusCode.Ok, reply.ProtocolStatus.Code); Assert.True(reply.Register.ServerHandle > 0); return reply; } private static async Task UnregisterLiveSessionAsync( MxAccessStaSession session, int serverHandle, string correlationId) { MxCommandReply unregisterReply = await session.DispatchAsync(new StaCommand( "session-1", correlationId, new MxCommand { Kind = MxCommandKind.Unregister, Unregister = new UnregisterCommand { ServerHandle = serverHandle, }, })); Assert.Equal(ProtocolStatusCode.Ok, unregisterReply.ProtocolStatus.Code); } }