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

namespace XUnitTest.Net;

[Collection("Net")]
[TestCaseOrderer("NewLife.UnitTest.DefaultOrderer", "NewLife.UnitTest")]
public class TcpSessionTests
{
    static TcpSessionTests()
    {
        var ip4 = IPAddress.Parse("127.0.0.66");
        //var ip6 = IPAddress.Parse("::66");
        var ip6 = IPAddress.Parse("::1");

        var ips = NetHelper.GetIPsWithCache().Where(e => !IPAddress.IsLoopback(e)).ToArray();
        ip4 = ips.FirstOrDefault(e => e.IsIPv4()) ?? ip4;
        ip6 = ips.FirstOrDefault(e => !e.IsIPv4()) ?? ip6;

        // 修改DnsResolver解析,把域名 newlifex.com 指向本地
        if (DnsResolver.Instance is DnsResolver resolver)
        {
            resolver.Set("test.newlifex.com", [ip4, ip6]);
        }

        var asm = typeof(TcpSessionTests).Assembly;
        //var key = asm.GetManifestResourceStream("XUnitTest.certs.newlifex.com.pem").ToStr();
        //var pkey = asm.GetManifestResourceStream("XUnitTest.certs.newlifex.com.privatekey.pem").ToStr();
        var pfx = asm.GetManifestResourceStream("XUnitTest.certs.newlifex.com.pfx").ReadBytes(-1);
        //var cert = X509Certificate2.CreateFromPem(key, pkey);
        //var cert = X509Certificate2.CreateFromEncryptedPem(key, pkey, "123456");
#if NET9_0_OR_GREATER
        var cert = X509CertificateLoader.LoadPkcs12(pfx, "123456");
#else
        var cert = new X509Certificate2(pfx, "123456", X509KeyStorageFlags.DefaultKeySet);
#endif

        // 启动NetServer
        var server4 = new HttpServer
        {
            Local = new NetUri(NetType.Https, ip4, 443),
            Certificate = cert,
            SslProtocol = SslProtocols.Tls12,
            Log = XTrace.Log,
        };
        server4.Start();

        var server6 = new HttpServer
        {
            Local = new NetUri(NetType.Https, ip6, 443),
            Certificate = cert,
            SslProtocol = SslProtocols.Tls12,
            Log = XTrace.Log,
        };
        server6.Start();
    }

    [Fact]
    public void BindTest()
    {
        var addr = NetHelper.GetIPsWithCache().FirstOrDefault(e => e.IsIPv4() && !IPAddress.IsLoopback(e));
        Assert.NotNull(addr);

        var uri = new NetUri(NetType.Udp, addr, 12345);
        var client = uri.CreateClient();
        client.Log = XTrace.Log;
        client.Open();
    }

    [Fact]
    public void BindTest2()
    {
        var addr = NetHelper.GetIPsWithCache().FirstOrDefault(e => e.IsIPv4() && !IPAddress.IsLoopback(e));
        Assert.NotNull(addr);

        var uri = new NetUri("https://test.newlifex.com");
        var client = uri.CreateRemote() as TcpSession;
        client.Local.Address = addr;

        Assert.Equal(0, client.Local.Port);

        client.Log = XTrace.Log;
        client.Open();

        Assert.Equal(client.Local.Address, addr);
        Assert.NotEqual(0, client.Local.Port);
        Assert.True(client.RemoteAddress.IsIPv4());
    }

    [Fact]
    public void BindTest3()
    {
        var addr = NetHelper.GetIPsWithCache().FirstOrDefault(e => e.IsIPv4() && !IPAddress.IsLoopback(e));
        Assert.NotNull(addr);

        var uri = new NetUri("https://test.newlifex.com");
        var client = uri.CreateRemote() as TcpSession;

        Assert.Equal(0, client.Local.Port);

        client.Log = XTrace.Log;
        client.Open();

        Assert.True(client.Local.Address.IsAny());
        Assert.NotEqual(0, client.Local.Port);
        //Assert.True(!client.RemoteAddress.IsIPv4());
    }

    [Fact]
    public void BindTest4()
    {
        Assert.True(Socket.OSSupportsIPv4);
        Assert.True(Socket.OSSupportsIPv6);

        var entry = Dns.GetHostEntry("newlifex.com");
        //var entry = Dns.GetHostEntry("newlifex.com.w.cdngslb.com");
        Assert.NotNull(entry);

        var addr = NetHelper.GetIPsWithCache().FirstOrDefault(e => !e.IsIPv4() && !IPAddress.IsLoopback(e));
        Assert.NotNull(addr);

        if (entry.AddressList.Any(_ => !_.IsIPv4()))
        {
            var uri = new NetUri("https://test.newlifex.com");
            var client = uri.CreateRemote();
            client.Local.Address = addr;
            client.Log = XTrace.Log;
            client.Open();
        }
    }

    /// <summary>加载测试自签名证书(内嵌 pfx)</summary>
    private static X509Certificate2 LoadTestCert()
    {
        var pfx = typeof(TcpSessionTests).Assembly.GetManifestResourceStream("XUnitTest.certs.newlifex.com.pfx")!.ReadBytes(-1);
#if NET9_0_OR_GREATER
        return X509CertificateLoader.LoadPkcs12(pfx, "123456");
#else
        return new X509Certificate2(pfx, "123456", X509KeyStorageFlags.DefaultKeySet);
#endif
    }

    /// <summary>SSL 回环 echo:256KB 逐字节一致(流式多轮读取)</summary>
    [Fact(DisplayName = "SSL_回环echo_256KB逐字节一致")]
    public async Task SslEcho_256KB()
    {
        using var cert = LoadTestCert();
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            SslProtocol = SslProtocols.Tls12,
            Certificate = cert,
            Log = XTrace.Log,
        };
        server.Received += (s, e) =>
        {
            if (s is INetSession session && e.Packet != null && e.Packet.Length > 0) session.Send(e.Packet);
        };
        server.Start();

        using var client = new TcpSession
        {
            Remote = new NetUri($"tcp://127.0.0.1:{server.Port}"),
            SslProtocol = SslProtocols.Tls12,
            AutoReceive = false,
            Log = XTrace.Log,
        };
        client.Open();

        var payload = new Byte[256 * 1024];
        Random.Shared.NextBytes(payload);
        _ = client.Send(payload);

        // 拉取读满(SSL 流按字节读,不依赖包边界)
        var offset = 0;
        while (offset < payload.Length)
        {
            using var pk = await client.ReceiveAsync(default).WaitAsync(TimeSpan.FromSeconds(15));
            Assert.NotNull(pk);
            Assert.True(pk!.Length > 0, "SSL回显中断");

            var bytes = pk.ToArray();
            Assert.True(payload.AsSpan(offset, bytes.Length).SequenceEqual(bytes), $"偏移 {offset} 数据不一致");
            offset += bytes.Length;
        }
    }

    /// <summary>SSL 客户端强制 RST:服务端应感知流异常并关闭会话,不悬挂</summary>
    [Fact(DisplayName = "SSL_客户端强制RST_服务端感知并关闭会话")]
    public void SslClientRst_ServerDetects()
    {
        var sessionReady = new ManualResetEventSlim(false);
        INetSession? serverSession = null;

        using var cert = LoadTestCert();
        using var server = new NetServer
        {
            Port = 0,
            ProtocolType = NetType.Tcp,
            SslProtocol = SslProtocols.Tls12,
            Certificate = cert,
            Log = XTrace.Log,
        };
        server.NewSession += (s, e) => { serverSession = e.Session; sessionReady.Set(); };
        server.Start();

        using var client = new TcpSession
        {
            Remote = new NetUri($"tcp://127.0.0.1:{server.Port}"),
            SslProtocol = SslProtocols.Tls12,
            Log = XTrace.Log,
        };
        client.Open();

        Assert.True(sessionReady.Wait(5000));
        Assert.NotNull(serverSession);

        // 先发一点数据确保服务端会话进入接收
        _ = client.Send("hello");
        Thread.Sleep(200);

        // 强制 RST:以 Linger0 直接关闭底层套接字,不发 close_notify、不走四次挥手
        var sock = client.Client;
        Assert.NotNull(sock);
        sock!.LingerState = new LingerOption(true, 0);
        sock.Close();

        // 服务端应在数秒内感知流异常并关闭会话(未修复时 SSL 读回调异常被吞,会话悬挂)
        var ss = (SessionBase)serverSession!.Session;
        for (var i = 0; i < 160 && ss.Active; i++) Thread.Sleep(50);
        Assert.False(ss.Active, "服务端应感知SSL客户端强制断开并关闭会话");
    }
}