69 lines
2.9 KiB
C#
69 lines
2.9 KiB
C#
using System.Reflection;
|
|
using QuantEngine.Infrastructure.External;
|
|
|
|
namespace QuantEngine.Core.Tests;
|
|
|
|
public class SecurityTests
|
|
{
|
|
[Theory]
|
|
[InlineData("/uapi/domestic-stock/v1/quotations/inquire-price", "FHKST01010100")]
|
|
[InlineData("/uapi/domestic-stock/v1/quotations/inquire-investor", "FHKST01010900")]
|
|
[InlineData("/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice", "FHKST03010100")]
|
|
public void AssertReadOnly_AllowsReadOnlyQuotationPaths(string path, string trId)
|
|
{
|
|
var client = CreateClient();
|
|
|
|
var ex = Record.Exception(() => InvokeAssertReadOnly(client, path, trId));
|
|
|
|
Assert.Null(ex);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("/uapi/domestic-stock/v1/trading/order-cash", "VTTC0802U")]
|
|
[InlineData("/uapi/domestic-stock/v1/quotations/inquire-price", "TTTC084000")]
|
|
[InlineData("/uapi/domestic-stock/v1/trading/order-cash", "FHKST01010100")]
|
|
public void AssertReadOnly_BlocksTradingPathsOrIds(string path, string trId)
|
|
{
|
|
var client = CreateClient();
|
|
|
|
var ex = Assert.Throws<TargetInvocationException>(() => InvokeAssertReadOnly(client, path, trId));
|
|
Assert.IsType<InvalidOperationException>(ex.InnerException);
|
|
Assert.Contains("BLOCKED", ex.InnerException!.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void AssertReadOnly_BlocksKnownTradingTrIdPrefixes()
|
|
{
|
|
var client = CreateClient();
|
|
|
|
var ex = Assert.Throws<TargetInvocationException>(() => InvokeAssertReadOnly(client, "/uapi/domestic-stock/v1/quotations/inquire-price", "VTTC8434R00"));
|
|
Assert.IsType<InvalidOperationException>(ex.InnerException);
|
|
Assert.Contains("TR_ID", ex.InnerException!.Message);
|
|
}
|
|
|
|
private static KisApiClient CreateClient()
|
|
{
|
|
Environment.SetEnvironmentVariable("KIS_APP_Key_TEST", "mock-key");
|
|
Environment.SetEnvironmentVariable("KIS_APP_Secret_TEST", "mock-secret");
|
|
return new KisApiClient(new HttpClient(new DummyHandler()), new NoopConnectionFactory());
|
|
}
|
|
|
|
private static void InvokeAssertReadOnly(KisApiClient client, string path, string trId)
|
|
{
|
|
var method = typeof(KisApiClient).GetMethod("AssertReadOnly", BindingFlags.Instance | BindingFlags.NonPublic)
|
|
?? throw new InvalidOperationException("AssertReadOnly method not found.");
|
|
method.Invoke(client, new object[] { path, trId });
|
|
}
|
|
|
|
private sealed class DummyHandler : HttpMessageHandler
|
|
{
|
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
|
=> Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK));
|
|
}
|
|
|
|
private sealed class NoopConnectionFactory : QuantEngine.Infrastructure.Data.IDbConnectionFactory
|
|
{
|
|
public System.Data.IDbConnection CreateConnection() => throw new NotSupportedException("Not needed for read-only guard tests.");
|
|
}
|
|
}
|