[fix] 修正IPacket.ReadBytes导致链表式数据读取错误
智能大石头 authored at 2024-12-07 00:14:15
7.88 KiB
NewLife.Remoting
using System;
using System.Collections.Generic;
using System.Linq;
using NewLife;
using NewLife.Caching;
using NewLife.Data;
using NewLife.Log;
using NewLife.Model;
using NewLife.Net;
using NewLife.Remoting;
using Xunit;

namespace XUnitTest.Remoting;

[TestCaseOrderer("NewLife.UnitTest.DefaultOrderer", "NewLife.UnitTest")]
public class ApiTest : DisposeBase
{
    private static ApiServer _Server;
    private static ApiClient _Client;
    private String _Uri;

    public ApiTest()
    {
        //var port = Rand.Next(12348);
        var port = 12348;

        if (_Server == null)
        {
            _Server = new ApiServer(port)
            {
                Log = XTrace.Log,
                //EncoderLog = XTrace.Log,
                ShowError = true,
            };
            _Server.Handler = new TokenApiHandler { Host = _Server };
            _Server.Start();
        }

        _Uri = $"tcp://127.0.0.1:{port}";

        if (_Client == null)
        {
            var client = new ApiClient(_Uri)
            {
                //Log = XTrace.Log
            };
            //client.EncoderLog = XTrace.Log;
            _Client = client;
        }
    }

    //protected override void Dispose(Boolean disposing)
    //{
    //    base.Dispose(disposing);

    //    _Server.TryDispose();
    //}

    //[Order(1)]
    [Fact(DisplayName = "基础Api测试")]
    public async void BasicTest()
    {
        var apis = await _Client.InvokeAsync<String[]>("api/all");
        Assert.NotNull(apis);
        Assert.Equal(2, apis.Length);
        Assert.Equal("String[] Api/All()", apis[0]);
        Assert.Equal("Object Api/Info(String state)", apis[1]);
        //Assert.Equal("Packet Api/Info2(Packet state)", apis[2]);
    }

    //[Order(2)]
    [Theory(DisplayName = "参数测试")]
    [InlineData("12345678", "ABCDEFG")]
    [InlineData("ABCDEFG", "12345678")]
    public async void InfoTest(String state, String state2)
    {
        var infs = await _Client.InvokeAsync<IDictionary<String, Object>>("api/info", new { state, state2 });
        Assert.NotNull(infs);
        Assert.Equal(Environment.MachineName, infs["MachineName"]);
        //Assert.Equal(Environment.UserName, infs["UserName"]);

        Assert.Equal(state, infs["state"]);
        Assert.Null(infs["state2"]);
    }

    ////[Order(3)]
    //[Fact(DisplayName = "二进制测试")]
    //public async void Info2Test()
    //{
    //    var buf = Rand.NextBytes(32);

    //    var pk = await _Client.InvokeAsync<Packet>("api/info2", buf);
    //    Assert.NotNull(pk);
    //    Assert.True(pk.Total > buf.Length);
    //    Assert.Equal(buf, pk.Slice(pk.Total - buf.Length, -1).ToArray());
    //}

    //[Order(4)]
    [Fact(DisplayName = "异常请求")]
    public async void ErrorTest()
    {
        var ex = await Assert.ThrowsAsync<ApiException>(() => _Client.InvokeAsync<Object>("api/info3"));

        Assert.NotNull(ex);
        Assert.Equal(404, ex.Code);
        Assert.Equal("无法找到名为[api/info3]的服务!", ex.Message);

        var uri = new NetUri(_Client.Servers[0]);
        Assert.Equal(uri + "/api/info3", ex.Source);
    }

    [Theory(DisplayName = "令牌测试")]
    [InlineData("12345678", "ABCDEFG")]
    [InlineData("ABCDEFG", "12345678")]
    public async void TokenTest(String token, String state)
    {
        var client = new ApiClient(_Uri)
        {
            //Log = XTrace.Log,
            Token = token,
        };

        var infs = await client.InvokeAsync<IDictionary<String, Object>>("api/info", new { state });
        Assert.NotNull(infs);
        Assert.Equal(token, infs["token"]);

        // 另一个客户端,共用令牌,应该可以拿到上一次状态数据
        var client2 = new ApiClient(_Uri)
        {
            //Log = XTrace.Log,
            Token = token,
        };

        infs = await client2.InvokeAsync<IDictionary<String, Object>>("api/info");
        Assert.NotNull(infs);
        //Assert.Equal(state, infs["LastState"]);
    }

    [Fact]
    public async void BigMessage()
    {
        using var server = new ApiServer(12399);
        server.Log = XTrace.Log;
        server.EncoderLog = XTrace.Log;
        server.Register<BigController>();
        server.Start();

        using var client = new ApiClient("tcp://127.0.0.1:12399");

        var buf = new Byte[5 * 8 * 1024];
        Array.Fill(buf, (Byte)'a');
        var rs = await client.InvokeAsync<Packet>("big/test", buf);

        Assert.NotNull(rs);
        Assert.Equal(buf.Length, rs.Total);

        var buf2 = buf.Select(e => (Byte)(e ^ 'x')).ToArray();
        Assert.True(rs.ToArray().SequenceEqual(buf2));

        var ret = client.InvokeOneWay("big/TestOneWay", buf);
    }

    [Fact]
    public async void BigMessage64k()
    {
        using var server = new ApiServer(12399);
        server.Log = XTrace.Log;
        server.EncoderLog = XTrace.Log;
        server.Register<BigController>();
        server.Start();

        using var client = new ApiClient("tcp://127.0.0.1:12399");

        var buf = new Byte[65 * 1024];
        Array.Fill(buf, (Byte)'a');
        var rs = await client.InvokeAsync<Packet>("big/test", buf);

        Assert.NotNull(rs);
        Assert.Equal(buf.Length, rs.Total);

        var buf2 = buf.Select(e => (Byte)(e ^ 'x')).ToArray();
        Assert.True(rs.ToArray().SequenceEqual(buf2));

        var ret = client.InvokeOneWay("big/TestOneWay", buf);
    }

    class BigController
    {
        public IPacket Test(IPacket pk)
        {
            //Assert.Equal(5 * 8 * 1024, pk.Total);

            var buf = pk.ReadBytes();
            buf = buf.Select(e => (Byte)(e ^ 'x')).ToArray();

            return (ArrayPacket)buf;
        }

        public void TestOneWay(IPacket pk)
        {
            Assert.Equal(5 * 8 * 1024, pk.Total);
        }
    }

    [Fact]
    public void ServiceProviderTest()
    {
        var cache = new MemoryCache();
        var ioc = ObjectContainer.Current;
        ioc.AddSingleton<ICache>(cache);
        ioc.AddTransient<SPService>();

        using var server = new ApiServer(12349);
        server.ServiceProvider = ioc.BuildServiceProvider();
        server.Log = XTrace.Log;

        server.Register<SPController>();
        server.Start();

        using var client = new ApiClient("tcp://127.0.0.1:12349");
        var rs = client.Invoke<Int64>("SP/Test", new { key = "stone" });
        Assert.Equal(123, rs);
    }

    class SPController
    {
        private readonly ICache _cache;
        private readonly SPService _service;

        public SPController(ICache cache, SPService service)
        {
            _cache = cache;
            _service = service;
        }

        public Int64 Test(String key) => _service.Test(key);
    }

    class SPService
    {
        private readonly ICache _cache;

        public SPService(ICache cache) => _cache = cache;

        public Int64 Test(String key) => _cache.Increment(key, 123);
    }

    [Fact]
    public async void SimpleType()
    {
        using var server = new ApiServer(12377);
        server.Log = XTrace.Log;
        server.EncoderLog = XTrace.Log;
        server.Register<SimpleController>();
        server.Start();

        using var client = new ApiClient($"tcp://127.0.0.1:{server.Port}");

        var rs = await client.InvokeAsync<String>("Simple/Say", "Hello NewLife!");
        Assert.Equal("Say: Hello NewLife!", rs);

        var time = DateTime.Now;
        rs = await client.InvokeAsync<String>("Simple/Login", time);
        Assert.Equal($"Login: {time.ToFullString()}", rs);

        rs = await client.InvokeAsync<String>("Simple/Login", time.ToFullString());
        Assert.Equal($"Login: {time.ToFullString()}", rs);

        rs = await client.InvokeAsync<String>("Simple/Login", time.ToString());
        Assert.Equal($"Login: {time.ToFullString()}", rs);
    }

    class SimpleController
    {
        public String Say(String text) => $"Say: {text}";

        public String Login(DateTime time) => $"Login: {time.ToFullString()}";
    }
}