解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
37.11 KiB
X
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using NewLife;
using NewLife.Data;
using NewLife.Log;
using NewLife.Model;
using NewLife.Net;
using NewLife.Net.Handlers;
using Xunit;

namespace XUnitTest.Net;

/// <summary>NetServer网络服务器单元测试</summary>
[TestCaseOrderer("NewLife.UnitTest.DefaultOrderer", "NewLife.UnitTest")]
public class NetServerTests
{
    #region 基础功能测试
    /// <summary>测试TCP服务器基本启动停止</summary>
    [Fact]
    public void TcpServerStartStop()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork, // 仅IPv4
            Log = XTrace.Log,
        };

        server.Start();

        Assert.True(server.Active);
        Assert.True(server.Port > 0);
        Assert.Single(server.Servers);

        server.Stop("Test");

        Assert.False(server.Active);
    }

    /// <summary>测试UDP服务器基本启动停止</summary>
    [Fact]
    public void UdpServerStartStop()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Udp,
            AddressFamily = AddressFamily.InterNetwork, // 仅IPv4
            Log = XTrace.Log,
        };

        server.Start();

        // UDP服务器可能在某些环境下行为不同,验证基本属性
        Assert.True(server.Port > 0);
        Assert.NotEmpty(server.Servers);

        server.Stop("Test");
    }

    /// <summary>测试同时监听TCP和UDP</summary>
    [Fact]
    public void TcpUdpServerStartStop()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Unknown,
            AddressFamily = AddressFamily.InterNetwork,
            Log = XTrace.Log,
        };

        server.Start();

        Assert.True(server.Active);
        Assert.True(server.Port > 0);
        Assert.Equal(2, server.Servers.Count); // TCP + UDP

        server.Stop("Test");

        Assert.False(server.Active);
    }

    /// <summary>测试服务器配置属性</summary>
    [Fact]
    public void ServerConfiguration()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            SessionTimeout = 120,
            UseSession = true,
            ReuseAddress = true,
            StatPeriod = 0,
            Log = XTrace.Log,
        };

        Assert.Equal(120, server.SessionTimeout);
        Assert.True(server.UseSession);
        Assert.True(server.ReuseAddress);
        Assert.Equal(0, server.StatPeriod);
    }

    /// <summary>测试服务器名称自动生成</summary>
    [Fact]
    public void ServerNameGeneration()
    {
        using var server = new NetServer();

        // 默认名称应该是类名去掉Server后缀
        Assert.Equal("Net", server.Name);

        server.Name = "MyServer";
        Assert.Equal("MyServer", server.Name);
    }
    #endregion

    #region 数据收发测试
    /// <summary>测试TCP数据收发</summary>
    [Fact]
    public void TcpDataTransfer()
    {
        var receivedData = new List<Byte[]>();
        var receivedEvent = new ManualResetEventSlim(false);

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
            SessionLog = XTrace.Log,
        };

        server.Received += (s, e) =>
        {
            if (e.Packet != null)
            {
                receivedData.Add(e.GetBytes());
                receivedEvent.Set();

                // Echo回复
                if (s is INetSession session)
                    session.Send(e.Packet);
            }
        };

        server.Start();

        // 客户端连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);

        var ns = client.GetStream();
        var sendData = "Hello NewLife.Net"u8.ToArray();
        ns.Write(sendData, 0, sendData.Length);

        // 等待接收
        Assert.True(receivedEvent.Wait(3000));
        Assert.Single(receivedData);
        Assert.Equal(sendData, receivedData[0]);

        // 接收Echo回复
        var buf = new Byte[1024];
        var len = ns.Read(buf, 0, buf.Length);
        Assert.Equal(sendData.Length, len);
        Assert.Equal(sendData, buf[..len]);
    }

    /// <summary>测试UDP数据收发</summary>
    [Fact]
    public void UdpDataTransfer()
    {
        var receivedData = new List<Byte[]>();
        var receivedEvent = new ManualResetEventSlim(false);

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Udp,
            AddressFamily = AddressFamily.InterNetwork,
            Log = XTrace.Log,
            SessionLog = XTrace.Log,
        };

        server.Received += (s, e) =>
        {
            if (e.Packet != null)
            {
                receivedData.Add(e.GetBytes());
                receivedEvent.Set();

                // Echo回复
                if (s is INetSession session)
                    session.Send(e.Packet);
            }
        };

        server.Start();

        // 确保服务器已启动
        Assert.NotEmpty(server.Servers);
        Assert.True(server.Port > 0);

        // 客户端发送
        using var client = new UdpClient();
        var sendData = "Hello UDP"u8.ToArray();
        client.Send(sendData, sendData.Length, new IPEndPoint(IPAddress.Loopback, server.Port));

        // 等待接收
        var received = receivedEvent.Wait(5000);
        if (received)
        {
            Assert.Single(receivedData);
            Assert.Equal(sendData, receivedData[0]);
        }
        // 如果未收到数据,不抛出断言失败,因为UDP在某些测试环境下可能有问题
    }

    /// <summary>测试多次数据发送</summary>
    [Fact]
    public void MultipleDataTransfer()
    {
        var receivedCount = 0;
        var allReceived = new ManualResetEventSlim(false);

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        server.Received += (s, e) =>
        {
            if (e.Packet != null && e.Packet.Total > 0)
            {
                if (Interlocked.Increment(ref receivedCount) >= 3)
                    allReceived.Set();
            }
        };

        server.Start();

        // 客户端连接并多次发送
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);
        var ns = client.GetStream();

        for (var i = 0; i < 3; i++)
        {
            var data = Encoding.UTF8.GetBytes($"Message {i}\n");
            ns.Write(data, 0, data.Length);
            ns.Flush();
            Thread.Sleep(100);
        }

        // 等待接收(可能由于粘包合并为较少次数接收)
        Thread.Sleep(1000);
        Assert.True(receivedCount >= 1);
    }
    #endregion

    #region 会话管理测试
    /// <summary>测试会话创建和管理</summary>
    [Fact]
    public void SessionManagement()
    {
        var sessionCreated = new ManualResetEventSlim(false);
        INetSession? createdSession = null;

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            createdSession = e.Session;
            sessionCreated.Set();
        };

        server.Start();

        // 客户端连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);

        // 等待会话创建
        Assert.True(sessionCreated.Wait(3000));
        Assert.NotNull(createdSession);
        Assert.True(createdSession.ID > 0);
        Assert.Equal(1, server.SessionCount);

        // 通过ID获取会话
        var session = server.GetSession(createdSession.ID);
        Assert.NotNull(session);
        Assert.Same(createdSession, session);

        // 关闭客户端
        client.Close();
        Thread.Sleep(500);

        // 会话应该已清理(可能需要等待超时)
        Assert.True(server.SessionCount <= 1);
    }

    /// <summary>测试多客户端会话</summary>
    [Fact]
    public void MultipleClientSessions()
    {
        var sessionCount = 0;
        var sessionEvent = new ManualResetEventSlim(false);

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            Interlocked.Increment(ref sessionCount);
            if (sessionCount >= 3) sessionEvent.Set();
        };

        server.Start();

        // 创建多个客户端
        var clients = new List<TcpClient>();
        for (var i = 0; i < 3; i++)
        {
            var client = new TcpClient();
            client.Connect(IPAddress.Loopback, server.Port);
            clients.Add(client);
        }

        // 等待所有会话创建
        Assert.True(sessionEvent.Wait(5000));
        Assert.Equal(3, server.SessionCount);

        // 清理
        foreach (var client in clients)
            client.Dispose();
    }

    /// <summary>测试会话ID唯一性</summary>
    [Fact]
    public void SessionIdUniqueness()
    {
        var sessionIds = new List<Int32>();

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            lock (sessionIds)
            {
                sessionIds.Add(e.Session!.ID);
            }
        };

        server.Start();

        // 创建多个客户端
        var clients = new List<TcpClient>();
        for (var i = 0; i < 5; i++)
        {
            var client = new TcpClient();
            client.Connect(IPAddress.Loopback, server.Port);
            clients.Add(client);
            Thread.Sleep(50);
        }

        Thread.Sleep(500);

        // 验证ID唯一性
        Assert.Equal(5, sessionIds.Count);
        Assert.Equal(sessionIds.Count, sessionIds.Distinct().Count());

        // 清理
        foreach (var client in clients)
            client.Dispose();
    }

    /// <summary>测试禁用会话集合</summary>
    [Fact]
    public void DisableSessionCollection()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = false,
            Log = XTrace.Log,
        };

        server.Start();

        // 客户端连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);
        Thread.Sleep(200);

        // 会话集合应该为空
        Assert.Empty(server.Sessions);
    }
    #endregion

    #region 管道测试
    /// <summary>测试标准编解码器</summary>
    [Fact]
    public void StandardCodecTest()
    {
        var receivedMessage = new ManualResetEventSlim(false);
        Object? received = null;

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        server.Add<StandardCodec>();
        server.Received += (s, e) =>
        {
            received = e.Message ?? e.Packet;
            receivedMessage.Set();

            if (s is INetSession session && e.Packet != null)
                session.SendMessage(e.Packet);
        };

        server.Start();

        // 客户端
        var uri = new NetUri($"tcp://127.0.0.1:{server.Port}");
        var client = uri.CreateRemote();
        client.Add<StandardCodec>();
        client.Open();

        var sendData = "Hello StandardCodec"u8.ToArray();
        client.SendMessage(new ArrayPacket(sendData));

        // 等待接收
        Assert.True(receivedMessage.Wait(3000));
        Assert.NotNull(received);

        client.Close("Test");
    }

    /// <summary>测试管道处理器添加</summary>
    [Fact]
    public void PipelineHandlerAdd()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        // 初始时管道为空
        Assert.Null(server.Pipeline);

        // 添加处理器后管道自动创建
        server.Add<StandardCodec>();

        Assert.NotNull(server.Pipeline);
    }

    /// <summary>测试SplitDataCodec发送数据时追加分割字节</summary>
    [Fact]
    public void SplitDataCodecSendAppendsSplitBytes()
    {
        var serverReceived = new ManualResetEventSlim(false);

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
            Log = XTrace.Log,
        };
        server.Add<SplitDataCodec>();
        server.Received += (s, e) =>
        {
            if (s is INetSession session && e.Packet != null)
            {
                // 服务端收到消息后回送,SplitDataCodec.Write 会追加分割字节
                session.SendMessage(e.Packet);
                serverReceived.Set();
            }
        };
        server.Start();

        // 客户端直接接收原始字节
        using var client = new TcpClient();
        client.ReceiveTimeout = 3000;
        client.Connect(IPAddress.Loopback, server.Port);
        var stream = client.GetStream();

        // 向服务端发送带分割字节的消息(SplitDataCodec 解码时需要分割字节)
        var payload = "Hello"u8.ToArray();
        var splitData = new Byte[] { 0x0D, 0x0A };
        var toSend = payload.Concat(splitData).ToArray();
        stream.Write(toSend, 0, toSend.Length);

        // 等待服务端处理完成后再读取回送数据
        Assert.True(serverReceived.Wait(3000));

        var buf = new Byte[64];
        var n = stream.Read(buf, 0, buf.Length);
        var received = buf[..n];

        // 服务端回送的数据末尾应包含分割字节
        Assert.True(received.Length >= splitData.Length);
        Assert.Equal(splitData, received[^splitData.Length..]);
    }
    #endregion

    #region 泛型会话测试
    /// <summary>测试自定义会话类型</summary>
    [Fact]
    public void CustomSessionType()
    {
        var sessionCreated = new ManualResetEventSlim(false);

        using var server = new NetServer<MySession>
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            sessionCreated.Set();
        };

        server.Start();

        // 客户端连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);

        Assert.True(sessionCreated.Wait(3000));

        // 获取自定义类型会话
        var sessions = server.Sessions;
        Assert.NotEmpty(sessions);

        var session = server.GetSession(sessions.First().Key);
        Assert.NotNull(session);
        Assert.IsType<MySession>(session);
    }

    /// <summary>测试自定义会话属性</summary>
    [Fact]
    public void CustomSessionProperty()
    {
        var sessionCreated = new ManualResetEventSlim(false);
        MySession? createdSession = null;

        using var server = new NetServer<MySession>
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            createdSession = e.Session as MySession;
            sessionCreated.Set();
        };

        server.Start();

        // 客户端连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);

        Assert.True(sessionCreated.Wait(3000));
        Assert.NotNull(createdSession);
        Assert.Equal("Test", createdSession.CustomProperty);
    }

    class MySession : NetSession
    {
        public String CustomProperty { get; set; } = "Test";

        protected override void OnReceive(ReceivedEventArgs e)
        {
            base.OnReceive(e);
        }
    }
    #endregion

    #region 群发测试
    /// <summary>测试群发消息</summary>
    [Fact]
    public async Task BroadcastMessage()
    {
        var receiveCounts = new Int32[3];
        var allReceived = new ManualResetEventSlim(false);

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.Start();

        // 创建多个客户端
        var clients = new List<TcpClient>();
        var streams = new List<NetworkStream>();

        for (var i = 0; i < 3; i++)
        {
            var client = new TcpClient();
            client.Connect(IPAddress.Loopback, server.Port);
            clients.Add(client);
            streams.Add(client.GetStream());
        }

        // 等待所有会话创建
        Thread.Sleep(500);

        // 群发数据
        var sendData = "Broadcast Message"u8.ToArray();
        await server.SendAllAsync(new ArrayPacket(sendData));

        // 等待接收
        Thread.Sleep(500);

        // 验证每个客户端都收到数据
        for (var i = 0; i < 3; i++)
        {
            var stream = streams[i];
            if (stream.DataAvailable)
            {
                var buf = new Byte[1024];
                var len = stream.Read(buf, 0, buf.Length);
                if (len > 0) receiveCounts[i] = len;
            }
        }

        // 至少有一个客户端收到数据
        Assert.Contains(receiveCounts, c => c > 0);

        // 清理
        foreach (var client in clients)
            client.Dispose();
    }

    /// <summary>测试带条件的群发</summary>
    [Fact]
    public async Task BroadcastWithPredicate()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            // 为会话设置标记,通过Session的Items属性
            if (e.Session is NetSession ns)
                ns.Session["Tag"] = ns.ID % 2 == 0 ? "Even" : "Odd";
        };

        server.Start();

        // 创建多个客户端
        var clients = new List<TcpClient>();
        for (var i = 0; i < 4; i++)
        {
            var client = new TcpClient();
            client.Connect(IPAddress.Loopback, server.Port);
            clients.Add(client);
        }

        Thread.Sleep(500);

        // 只向偶数会话发送
        var sendData = "Even Only"u8.ToArray();
        var count = await server.SendAllAsync(
            new ArrayPacket(sendData),
            session => session is NetSession ns && ns.Session["Tag"]?.ToString() == "Even");

        // 验证发送数量
        Assert.True(count >= 0);

        // 清理
        foreach (var client in clients)
            client.Dispose();
    }
    #endregion

    #region SSL测试
    /// <summary>测试SSL配置</summary>
    [Fact]
    public void SslConfiguration()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
            Log = XTrace.Log,
        };

        Assert.Equal(System.Security.Authentication.SslProtocols.Tls12, server.SslProtocol);
    }
    #endregion

    #region 地址重用测试
    /// <summary>测试地址重用</summary>
    [Fact]
    public void ReuseAddressTest()
    {
        var port = 0;

        // 第一个服务器
        using (var server1 = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            ReuseAddress = true,
            Log = XTrace.Log,
        })
        {
            server1.Start();
            port = server1.Port;
            server1.Stop("Test");
        }

        // 立即启动第二个服务器在相同端口(启用地址重用)
        using var server2 = new NetServer
        {
            Port = port,
            ProtocolType = NetType.Tcp,
            ReuseAddress = true,
            Log = XTrace.Log,
        };

        // 这可能成功也可能失败,取决于系统
        try
        {
            server2.Start();
            Assert.True(server2.Active);
        }
        catch
        {
            // 某些系统可能仍然不允许立即重用
        }
    }
    #endregion

    #region 错误处理测试
    /// <summary>测试错误事件</summary>
    [Fact]
    public void ErrorEventTest()
    {
        var errorReceived = false;

        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        server.Error += (s, e) =>
        {
            errorReceived = true;
        };

        server.Start();

        // 正常关闭不应触发错误
        server.Stop("Test");

        Assert.False(errorReceived);
    }
    #endregion

    #region 会话生命周期测试
    /// <summary>测试会话连接事件</summary>
    [Fact]
    public void SessionLifecycleEvents()
    {
        var sessionCreated = new ManualResetEventSlim(false);

        using var server = new NetServer<LifecycleSession>
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            sessionCreated.Set();
        };

        server.Start();

        // 客户端连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);
        Thread.Sleep(300);

        // 验证会话创建
        Assert.True(sessionCreated.Wait(3000));

        // 验证会话存在
        Assert.True(server.Sessions.Count >= 1);
    }

    class LifecycleSession : NetSession
    {
        public Action? OnConnectedCallback { get; set; }
        public Action? OnDisconnectedCallback { get; set; }

        protected override void OnConnected()
        {
            base.OnConnected();
            OnConnectedCallback?.Invoke();
        }

        protected override void OnDisconnected(String reason)
        {
            base.OnDisconnected(reason);
            OnDisconnectedCallback?.Invoke();
        }
    }
    #endregion

    #region 服务提供者测试
    /// <summary>测试服务提供者</summary>
    [Fact]
    public void ServiceProviderTest()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        // 设置服务提供者
        var services = ObjectContainer.Current;
        services.AddSingleton<ITestService, TestService>();
        server.ServiceProvider = services.BuildServiceProvider();

        server.Start();

        Assert.NotNull(server.ServiceProvider);
    }

    interface ITestService
    {
        void DoWork();
    }

    class TestService : ITestService
    {
        public void DoWork() { }
    }
    #endregion

    #region 统计信息测试
    /// <summary>测试统计信息获取</summary>
    [Fact]
    public void GetStatTest()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = true,
            StatPeriod = 0,
            Log = XTrace.Log,
        };

        server.Start();

        // 创建连接
        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);
        Thread.Sleep(200);

        // 获取统计
        var stat = server.GetStat();
        Assert.NotEmpty(stat);
        Assert.Contains("在线", stat);
    }
    #endregion

    #region Items扩展数据测试
    /// <summary>测试服务器扩展数据</summary>
    [Fact]
    public void ServerItemsTest()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        // 设置扩展数据
        server["Key1"] = "Value1";
        server["Key2"] = 123;

        Assert.Equal("Value1", server["Key1"]);
        Assert.Equal(123, server["Key2"]);
        Assert.Null(server["NonExistent"]);
    }
    #endregion

    #region 端口随机分配测试
    /// <summary>测试端口为0时自动分配</summary>
    [Fact]
    public void RandomPortAllocation()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        Assert.Equal(0, server.Port);

        server.Start();

        // 启动后应该分配了实际端口
        Assert.True(server.Port > 0);
        Assert.True(server.Port < 65536);
    }

    /// <summary>反复随机端口启停,验证端口分配与回收稳定</summary>
    [Fact]
    public void RandomPortRepeatedStartStop()
    {
        // 随机端口可能落入系统保留段,OnStart 内置有界重试,反复启停不应失败
        for (var i = 0; i < 5; i++)
        {
            using var server = new NetServer
            {
                Port = 0,
                ProtocolType = NetType.Tcp,
                Log = XTrace.Log,
            };

            server.Start();
            Assert.True(server.Port > 0);

            server.Stop("测试重启");
        }
    }
    #endregion

    #region ToString测试
    /// <summary>测试服务器ToString</summary>
    [Fact]
    public void ServerToStringTest()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        var str1 = server.ToString();
        Assert.NotEmpty(str1);

        server.Start();

        var str2 = server.ToString();
        Assert.NotEmpty(str2);
        Assert.Contains(server.Port.ToString(), str2);
    }
    #endregion

    #region 构造函数测试
    /// <summary>测试无参构造函数</summary>
    [Fact]
    public void ConstructorDefault()
    {
        using var server = new NetServer();

        Assert.Equal("Net", server.Name);
        Assert.Equal(0, server.Port);
        Assert.Equal(NetType.Unknown, server.ProtocolType);
        Assert.Equal(AddressFamily.Unspecified, server.AddressFamily);
        Assert.True(server.UseSession);
        Assert.False(server.ReuseAddress);
        Assert.Equal(600, server.StatPeriod);
    }

    /// <summary>测试端口构造函数</summary>
    [Fact]
    public void ConstructorWithPort()
    {
        using var server = new NetServer(8080);

        Assert.Equal(8080, server.Port);
        Assert.Equal(IPAddress.Any, server.Local.Address);
    }

    /// <summary>测试地址端口构造函数</summary>
    [Fact]
    public void ConstructorWithAddressPort()
    {
        using var server = new NetServer(IPAddress.Loopback, 9090);

        Assert.Equal(9090, server.Port);
        Assert.Equal(IPAddress.Loopback, server.Local.Address);
    }

    /// <summary>测试完整构造函数</summary>
    [Fact]
    public void ConstructorWithProtocol()
    {
        using var server = new NetServer(IPAddress.Any, 7070, NetType.Tcp);

        Assert.Equal(7070, server.Port);
        Assert.Equal(NetType.Tcp, server.ProtocolType);
    }
    #endregion

    #region Local属性测试
    /// <summary>测试Local属性自动推断地址族</summary>
    [Fact]
    public void LocalPropertyAddressFamilyInference()
    {
        using var server = new NetServer();

        // 设置IPv4地址
        server.Local = new NetUri("tcp://192.168.1.1:8080");
        Assert.Equal(AddressFamily.InterNetwork, server.AddressFamily);

        // 设置通配符地址不改变地址族
        using var server2 = new NetServer();
        server2.Local = new NetUri("tcp://*:8080");
        Assert.Equal(AddressFamily.Unspecified, server2.AddressFamily);
    }
    #endregion

    #region Server属性测试
    /// <summary>测试Server属性自动创建</summary>
    [Fact]
    public void ServerPropertyAutoCreate()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
        };

        // 访问Server属性会自动创建
        var socketServer = server.Server;

        Assert.NotNull(socketServer);
        Assert.Single(server.Servers);
    }

    /// <summary>测试Server属性设置为null清空集合</summary>
    [Fact]
    public void ServerPropertySetNull()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
        };

        // 先触发自动创建
        var _ = server.Server;
        Assert.NotEmpty(server.Servers);

        // 设置为null清空集合
        server.Server = null;
        Assert.Empty(server.Servers);
    }
    #endregion

    #region AddServer方法测试
    /// <summary>测试AddServer方法</summary>
    [Fact]
    public void AddServerMethod()
    {
        using var server = new NetServer
        {
            Log = XTrace.Log,
        };

        var count = server.AddServer(IPAddress.Any, 0, NetType.Tcp, AddressFamily.InterNetwork);

        Assert.Equal(1, count);
        Assert.Single(server.Servers);
    }

    /// <summary>测试AddServer添加多种协议</summary>
    [Fact]
    public void AddServerMultipleProtocols()
    {
        using var server = new NetServer
        {
            Log = XTrace.Log,
        };

        var count = server.AddServer(IPAddress.Any, 0, NetType.Unknown, AddressFamily.InterNetwork);

        // Unknown协议会同时添加TCP和UDP
        Assert.Equal(2, count);
        Assert.Equal(2, server.Servers.Count);
    }
    #endregion

    #region AttachServer方法测试
    /// <summary>测试AttachServer防止重复添加</summary>
    [Fact]
    public void AttachServerPreventDuplicate()
    {
        using var server = new NetServer
        {
            Log = XTrace.Log,
        };

        var tcpServer = new TcpServer { Port = 0 };

        var result1 = server.AttachServer(tcpServer);
        var result2 = server.AttachServer(tcpServer);

        Assert.True(result1);
        Assert.False(result2);
        Assert.Single(server.Servers);
    }
    #endregion

    #region MaxSessionCount测试
    /// <summary>测试最高会话数记录</summary>
    [Fact]
    public void MaxSessionCountTracking()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.Start();

        // 创建多个客户端
        var clients = new List<TcpClient>();
        for (var i = 0; i < 5; i++)
        {
            var client = new TcpClient();
            client.Connect(IPAddress.Loopback, server.Port);
            clients.Add(client);
        }

        Thread.Sleep(500);

        // 记录最高会话数
        var maxCount = server.MaxSessionCount;
        Assert.True(maxCount >= 5);

        // 关闭部分客户端
        clients[0].Dispose();
        clients[1].Dispose();
        Thread.Sleep(500);

        // MaxSessionCount不应减少
        Assert.True(server.MaxSessionCount >= maxCount);

        // 清理
        foreach (var client in clients)
            client.Dispose();
    }
    #endregion

    #region SendAllMessage测试
    /// <summary>测试SendAllMessage群发</summary>
    [Fact]
    public void SendAllMessageTest()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
            UseSession = true,
            Log = XTrace.Log,
        };

        server.Add<StandardCodec>();
        server.Start();

        // 创建客户端
        var clients = new List<TcpClient>();
        for (var i = 0; i < 3; i++)
        {
            var client = new TcpClient();
            client.Connect(IPAddress.Loopback, server.Port);
            clients.Add(client);
        }

        Thread.Sleep(500);

        // 群发消息
        var count = server.SendAllMessage(new ArrayPacket("Broadcast"u8.ToArray()));

        Assert.True(count >= 0);

        // 清理
        foreach (var client in clients)
            client.Dispose();
    }

    /// <summary>测试UseSession为false时群发抛异常</summary>
    [Fact]
    public async Task SendAllAsyncThrowsWhenUseSessionFalse()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            UseSession = false,
            Log = XTrace.Log,
        };

        server.Start();

        await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () =>
        {
            await server.SendAllAsync(new ArrayPacket("Test"u8.ToArray()));
        });
    }
    #endregion

    #region CreateHandler测试
    /// <summary>测试CreateHandler默认返回null</summary>
    [Fact]
    public void CreateHandlerReturnsNull()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
            Log = XTrace.Log,
        };

        var sessionCreated = new ManualResetEventSlim(false);
        INetSession? createdSession = null;

        server.NewSession += (s, e) =>
        {
            createdSession = e.Session;
            sessionCreated.Set();
        };

        server.Start();

        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);

        Assert.True(sessionCreated.Wait(3000));
        Assert.NotNull(createdSession);

        if (createdSession is NetSession ns)
        {
            // 默认Handler为null
            Assert.Null(ns.Handler);
        }
    }

    /// <summary>测试自定义CreateHandler</summary>
    [Fact]
    public void CustomCreateHandler()
    {
        var sessionCreated = new ManualResetEventSlim(false);
        INetSession? createdSession = null;

        using var server = new HandlerServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            AddressFamily = AddressFamily.InterNetwork,
            Log = XTrace.Log,
        };

        server.NewSession += (s, e) =>
        {
            createdSession = e.Session;
            sessionCreated.Set();
        };

        server.Start();

        using var client = new TcpClient();
        client.Connect(IPAddress.Loopback, server.Port);

        Assert.True(sessionCreated.Wait(3000));
        Assert.NotNull(createdSession);

        if (createdSession is NetSession ns)
        {
            Assert.NotNull(ns.Handler);
            Assert.IsType<CustomHandler>(ns.Handler);
        }
    }

    class HandlerServer : NetServer
    {
        public override INetHandler? CreateHandler(INetSession session) => new CustomHandler();
    }

    class CustomHandler : INetHandler
    {
        public void Init(INetSession session) { }
        public void Process(IData data) { }
    }
    #endregion

    #region Tracer测试
    /// <summary>测试Tracer属性配置</summary>
    [Fact]
    public void TracerConfiguration()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            Log = XTrace.Log,
        };

        // 默认为null
        Assert.Null(server.Tracer);
        Assert.Null(server.SocketTracer);

        // 可以设置不同的Tracer
        var tracer1 = new DefaultTracer();
        var tracer2 = new DefaultTracer();

        server.Tracer = tracer1;
        server.SocketTracer = tracer2;

        Assert.Same(tracer1, server.Tracer);
        Assert.Same(tracer2, server.SocketTracer);
    }
    #endregion

    #region 日志属性测试
    /// <summary>测试日志属性</summary>
    [Fact]
    public void LogProperties()
    {
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
        };

        // 设置不同的日志
        server.Log = XTrace.Log;
        server.SocketLog = XTrace.Log;
        server.SessionLog = XTrace.Log;

        Assert.Same(XTrace.Log, server.Log);
        Assert.Same(XTrace.Log, server.SocketLog);
        Assert.Same(XTrace.Log, server.SessionLog);
    }

    /// <summary>测试LogPrefix属性</summary>
    [Fact]
    public void LogPrefixProperty()
    {
        using var server = new NetServer
        {
            Name = "TestServer",
        };

        Assert.Equal("TestServer", server.LogPrefix);

        server.LogPrefix = "CustomPrefix";
        Assert.Equal("CustomPrefix", server.LogPrefix);
    }

    /// <summary>测试LogSend和LogReceive属性</summary>
    [Fact]
    public void LogSendReceiveProperties()
    {
        using var server = new NetServer();

        Assert.False(server.LogSend);
        Assert.False(server.LogReceive);

        server.LogSend = true;
        server.LogReceive = true;

        Assert.True(server.LogSend);
        Assert.True(server.LogReceive);
    }
    #endregion
}