feat(lmxproxy): phase 7 — integration tests, deployment to windev, v1 cutover
- Replaced STA dispatch thread with Task.Run pattern for COM interop - Fixed TypedValue oneof tracking with property-level _setCase field - Added x-api-key DelegatingHandler for gRPC metadata authentication - Fixed CheckApiKey RPC to validate request body key (not header) - Integration tests: 15/17 pass (reads, subscribes, API keys, connections) - 2 write tests pending (OnWriteComplete callback timing issue) - v2 service deployed on windev port 50100 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.LmxProxy.Host.MxAccess;
|
||||
|
||||
namespace ZB.MOM.WW.LmxProxy.Host.Tests.MxAccess
|
||||
{
|
||||
public class StaDispatchThreadTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task DispatchAsync_ExecutesOnStaThread()
|
||||
{
|
||||
using var sta = new StaDispatchThread("Test-STA");
|
||||
var threadId = await sta.DispatchAsync(() => Thread.CurrentThread.ManagedThreadId);
|
||||
threadId.Should().NotBe(Thread.CurrentThread.ManagedThreadId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DispatchAsync_ReturnsResult()
|
||||
{
|
||||
using var sta = new StaDispatchThread("Test-STA");
|
||||
var result = await sta.DispatchAsync(() => 42);
|
||||
result.Should().Be(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DispatchAsync_PropagatesException()
|
||||
{
|
||||
using var sta = new StaDispatchThread("Test-STA");
|
||||
Func<Task> act = () => sta.DispatchAsync<int>(() => throw new InvalidOperationException("test error"));
|
||||
await act.Should().ThrowAsync<InvalidOperationException>().WithMessage("test error");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DispatchAsync_Action_Completes()
|
||||
{
|
||||
using var sta = new StaDispatchThread("Test-STA");
|
||||
int value = 0;
|
||||
await sta.DispatchAsync(() => { value = 99; });
|
||||
value.Should().Be(99);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dispose_CompletesGracefully()
|
||||
{
|
||||
var sta = new StaDispatchThread("Test-STA");
|
||||
sta.Dispose(); // Should not throw
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DispatchAfterDispose_ThrowsObjectDisposedException()
|
||||
{
|
||||
var sta = new StaDispatchThread("Test-STA");
|
||||
sta.Dispose();
|
||||
Func<Task> act = () => sta.DispatchAsync(() => 42);
|
||||
act.Should().ThrowAsync<ObjectDisposedException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultipleDispatches_ExecuteInOrder()
|
||||
{
|
||||
using var sta = new StaDispatchThread("Test-STA");
|
||||
var results = new System.Collections.Concurrent.ConcurrentBag<int>();
|
||||
|
||||
var tasks = new Task[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
int idx = i;
|
||||
tasks[i] = sta.DispatchAsync(() => { results.Add(idx); });
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
results.Count.Should().Be(10);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StaThread_HasStaApartmentState()
|
||||
{
|
||||
using var sta = new StaDispatchThread("Test-STA");
|
||||
var apartmentState = await sta.DispatchAsync(() => Thread.CurrentThread.GetApartmentState());
|
||||
apartmentState.Should().Be(ApartmentState.STA);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user