云收藏 增加AI检测图片
This commit is contained in:
1 parent
b28940c02d
commit
b54a5f5310
36 files changed
+1978
-523
No files matched your search
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CsharpHttpHelper;
|
||||
using Work.Store.Api;
|
||||
|
||||
// Compile against Work.dll, AllBase.dll and Newtonsoft.Json.dll; run beside these assemblies.
|
||||
internal static class ApiTransportSmoke
|
||||
{
|
||||
private static void Check(bool passed)
|
||||
{
|
||||
if (!passed) throw new Exception("ApiTransport assertion failed.");
|
||||
}
|
||||
|
||||
private static async Task<T> Respond<T>(int status, string json, Func<ApiTransport, Task<T>> request)
|
||||
{
|
||||
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||
listener.Start();
|
||||
var server = Task.Run(() =>
|
||||
{
|
||||
using (var client = listener.AcceptTcpClient())
|
||||
using (var stream = client.GetStream())
|
||||
using (var reader = new StreamReader(stream, Encoding.ASCII, false, 1024, true))
|
||||
{
|
||||
while (!string.IsNullOrEmpty(reader.ReadLine())) { }
|
||||
var body = Encoding.UTF8.GetBytes(json);
|
||||
var header = Encoding.ASCII.GetBytes("HTTP/1.1 " + status + " Response\r\nContent-Type: application/json\r\nContent-Length: " + body.Length + "\r\nConnection: close\r\n\r\n");
|
||||
stream.Write(header, 0, header.Length);
|
||||
stream.Write(body, 0, body.Length);
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||
return await request(new ApiTransport("http://127.0.0.1:" + port));
|
||||
}
|
||||
finally
|
||||
{
|
||||
listener.Stop();
|
||||
await server;
|
||||
}
|
||||
}
|
||||
|
||||
private static Task<string> Send(ApiTransport transport)
|
||||
{
|
||||
return transport.SendAsync<string>("Test", MethodType.Get, authenticated: false, timeoutMilliseconds: 5000);
|
||||
}
|
||||
|
||||
public static async Task Main()
|
||||
{
|
||||
Check(await Respond(200, "{\"code\":0,\"success\":true,\"data\":\"ok\"}", Send) == "ok");
|
||||
Check(await Respond(200, "{\"code\":0,\"success\":true,\"data\":null}", Send) == null);
|
||||
Check(await Respond(200, "{\"success\":true,\"data\":null}", transport =>
|
||||
transport.SendAsync<int>("Test", MethodType.Get, authenticated: false)) == 0);
|
||||
Check((await Respond(200, "{\"success\":true,\"data\":[1,2]}", transport =>
|
||||
transport.SendAsync<int[]>("Test", MethodType.Get, authenticated: false)))[1] == 2);
|
||||
foreach (var status in new[] { 200, 500 })
|
||||
{
|
||||
await Respond(status, "{\"data\":null,\"code\":5000,\"msg\":\"semaphore limit\",\"traceId\":\"trace-1\",\"success\":false}", async transport =>
|
||||
{
|
||||
try { await Send(transport); throw new Exception("Expected ApiException."); }
|
||||
catch (ApiException ex)
|
||||
{
|
||||
Check(ex.Code == 5000 && ex.TraceId == "trace-1" && ex.Message.Contains("semaphore limit"));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
await Respond(200, "{\"code\":200,\"success\":false,\"data\":{}}", async transport =>
|
||||
{
|
||||
try { await Send(transport); throw new Exception("Expected ApiException."); }
|
||||
catch (ApiException ex) { Check(ex.Code == 200 && ex.ResponseData is Newtonsoft.Json.Linq.JObject); }
|
||||
return true;
|
||||
});
|
||||
foreach (var json in new[] { "not json", "[]", "null", "{\"code\":\"invalid\",\"success\":true}",
|
||||
"{\"code\":200,\"data\":\"legacy\"}", "{\"code\":200,\"success\":null}", "{}" })
|
||||
{
|
||||
await Respond(200, json, async transport =>
|
||||
{
|
||||
try { await Send(transport); throw new Exception("Expected response format error."); }
|
||||
catch (HttpException ex) { Check(ex.Message.Contains("Result")); }
|
||||
return true;
|
||||
});
|
||||
}
|
||||
await Respond(401, "{\"code\":401,\"success\":false,\"msg\":\"expired\"}", async transport =>
|
||||
{
|
||||
try { await Send(transport); throw new Exception("Expected authentication error."); }
|
||||
catch (HttpException ex) { Check(!ex.IsOnline && ex.Message == "expired"); }
|
||||
return true;
|
||||
});
|
||||
Check(await Respond(200, "{\"success\":true,\"data\":\"ok\"}", transport =>
|
||||
Task.Run(() => transport.GetRequired<string>("Test", MethodType.Get, authenticated: false))) == "ok");
|
||||
|
||||
var stalled = new TcpListener(IPAddress.Loopback, 0);
|
||||
stalled.Start();
|
||||
try
|
||||
{
|
||||
var transport = new ApiTransport("http://" + stalled.LocalEndpoint);
|
||||
try
|
||||
{
|
||||
await transport.SendAsync<string>("Test", MethodType.Get, authenticated: false, timeoutMilliseconds: 250);
|
||||
throw new Exception("Expected timeout.");
|
||||
}
|
||||
catch (HttpException ex) { Check(ex.Message.Contains("超时")); }
|
||||
}
|
||||
finally { stalled.Stop(); }
|
||||
Console.WriteLine("ApiTransport smoke checks passed.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using AllBase.Helper;
|
||||
using AllBase;
|
||||
using AllBase.Model;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Work.Services;
|
||||
|
||||
// Compile against the built Work.dll, AllBase.dll and Newtonsoft.Json.dll and run in an isolated directory.
|
||||
internal static class GoodsComplianceSmoke
|
||||
{
|
||||
private static void Check(bool passed)
|
||||
{
|
||||
if (!passed) throw new Exception("商品合规自测失败");
|
||||
}
|
||||
|
||||
public static void Main()
|
||||
{
|
||||
var user = Guid.NewGuid().ToString();
|
||||
BaseClass.UserName = user;
|
||||
GlobalConfig.GlobalSettings.GoodsCompliance = new ComplianceOptions { Keywords = "测试" };
|
||||
var cloud = new ComplianceGoods { id = "123", type = ComplianceGoods.Cloud };
|
||||
var library = new ComplianceGoods { id = "123", type = ComplianceGoods.Library };
|
||||
var attempted = new List<ComplianceGoods>();
|
||||
var failures = new List<string>();
|
||||
var batch = GoodsComplianceService.DetectSelectedAsync(new[] { cloud, cloud, library }, item =>
|
||||
{
|
||||
attempted.Add(item);
|
||||
throw new InvalidOperationException("读取失败");
|
||||
}, (id, status) => { if (status == "失败:读取失败") failures.Add(id); }).GetAwaiter().GetResult();
|
||||
Check(attempted.SequenceEqual(new[] { cloud, library }) && failures.Count == 2);
|
||||
var file = System.IO.Directory.GetFiles(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
|
||||
"data", "config"), "goods_compliance_" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(user)) + ".json").Single();
|
||||
Check(Newtonsoft.Json.JsonConvert.DeserializeObject<List<ComplianceGoods>>(System.IO.File.ReadAllText(file))
|
||||
.Select(x => x.type).SequenceEqual(new[] { cloud.type, library.type }));
|
||||
Check(batch.Safe == 0 && batch.Risk == 0 && batch.Failed == 2 && batch.Unfinished == 0);
|
||||
using (var stop = new System.Threading.CancellationTokenSource())
|
||||
{
|
||||
attempted.Clear();
|
||||
var stopped = GoodsComplianceService.DetectSelectedAsync(new[] { cloud, library }, item =>
|
||||
{
|
||||
attempted.Add(item);
|
||||
stop.Cancel();
|
||||
return new Product { ProductId = item.id };
|
||||
}, (id, status) => { }, stop.Token).GetAwaiter().GetResult();
|
||||
Check(attempted.SequenceEqual(new[] { cloud }) && stopped.Unfinished == 2 && stopped.Failed == 0);
|
||||
Check(Newtonsoft.Json.JsonConvert.DeserializeObject<List<ComplianceGoods>>(System.IO.File.ReadAllText(file)).Count == 2);
|
||||
}
|
||||
var words = GoodsComplianceService.Keywords("广告,测试,abc 促销;ABC|示例");
|
||||
Check(words.Length == 5);
|
||||
Check(GoodsComplianceService.Matches("ABC广告", words).SequenceEqual(new[] { "广告", "abc" }));
|
||||
Check(GoodsComplianceService.Matches("普通商品", words).Length == 0);
|
||||
var invalidImage = new Product { ProductId = "bad-image", MainImages = new List<string> { "file:///image.jpg" } };
|
||||
var statuses = new List<string>();
|
||||
GoodsComplianceService.DetectSelectedAsync(new[] { cloud }, item => invalidImage,
|
||||
(id, status) => statuses.Add(status)).GetAwaiter().GetResult();
|
||||
Check(statuses.SequenceEqual(new[] { "读取详情中", "正在检测第 1 张图片", "失败:第 1 张图片检测失败:图片链接必须为 HTTP 或 HTTPS 地址。" }));
|
||||
var products = new[] { new Product(), new Product { ProductId = "empty" }, invalidImage };
|
||||
var callbacks = new List<Product>();
|
||||
GoodsComplianceService.DetectAsync(products, new ComplianceOptions { Keywords = "测试" }, (product, result) =>
|
||||
{
|
||||
Check(result.Error != null);
|
||||
if (product == invalidImage) Check(result.Error.Contains("第 1 张图片") && result.Error.Contains("HTTP"));
|
||||
callbacks.Add(product);
|
||||
}).GetAwaiter().GetResult();
|
||||
Check(callbacks.SequenceEqual(products));
|
||||
System.IO.File.Delete(file);
|
||||
Console.WriteLine("商品合规队列与匹配自测通过");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CsharpHttpHelper;
|
||||
|
||||
internal static class HttpHelperAsyncSmoke
|
||||
{
|
||||
public static async Task Main()
|
||||
{
|
||||
await CheckRequests(false);
|
||||
await CheckRequests(true);
|
||||
}
|
||||
|
||||
private static async Task CheckRequests(bool asynchronous)
|
||||
{
|
||||
var listener = new TcpListener(IPAddress.Loopback, 0);
|
||||
listener.Start();
|
||||
try
|
||||
{
|
||||
string url = "http://" + listener.LocalEndpoint + "/";
|
||||
var pending = asynchronous ? HttpHelper.PostAsync(url, "hello") : Task.Run(() => HttpHelper.Post(url, "hello"));
|
||||
using (var client = await listener.AcceptTcpClientAsync())
|
||||
using (var stream = client.GetStream())
|
||||
using (var reader = new StreamReader(stream, Encoding.ASCII, false, 1024, true))
|
||||
{
|
||||
if (!reader.ReadLine().StartsWith("POST ", StringComparison.OrdinalIgnoreCase))
|
||||
throw new Exception("Expected POST");
|
||||
while (!string.IsNullOrEmpty(reader.ReadLine())) { }
|
||||
var reply = Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\n\r\n");
|
||||
stream.Write(reply, 0, reply.Length);
|
||||
var body = new char[5];
|
||||
if (reader.ReadBlock(body, 0, body.Length) != 5 || new string(body) != "hello")
|
||||
throw new Exception("POST body mismatch");
|
||||
|
||||
reply = Encoding.ASCII.GetBytes("HTTP/1.1 400 Bad Request\r\nContent-Length: 7\r\nConnection: close\r\n\r\ninvalid");
|
||||
stream.Write(reply, 0, reply.Length);
|
||||
}
|
||||
var result = await pending;
|
||||
if (result.StatusCode != HttpStatusCode.BadRequest || result.Html != "invalid")
|
||||
throw new Exception("Missing error response");
|
||||
|
||||
var get = asynchronous ? HttpHelper.GetAsync(url) : Task.Run(() => HttpHelper.Get(url));
|
||||
using (var client = await listener.AcceptTcpClientAsync())
|
||||
using (var stream = client.GetStream())
|
||||
using (var reader = new StreamReader(stream, Encoding.ASCII, false, 1024, true))
|
||||
{
|
||||
if (!reader.ReadLine().StartsWith("GET ", StringComparison.OrdinalIgnoreCase))
|
||||
throw new Exception("Expected GET");
|
||||
while (!string.IsNullOrEmpty(reader.ReadLine())) { }
|
||||
var reply = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 5\r\nConnection: close\r\n\r\n\uFEFFok");
|
||||
stream.Write(reply, 0, reply.Length);
|
||||
}
|
||||
if ((await get).Html != "\uFEFFok") throw new Exception("Expected GET response to retain its BOM");
|
||||
|
||||
var item = new HttpItem { URL = url, Timeout = 250 };
|
||||
var stalled = asynchronous ? HttpHelper.RequestAsync(item) : Task.Run(() => HttpHelper.Request(item));
|
||||
if (await Task.WhenAny(stalled, Task.Delay(5000)) != stalled || string.IsNullOrEmpty((await stalled).Html))
|
||||
throw new Exception("Expected a timeout result");
|
||||
}
|
||||
finally
|
||||
{
|
||||
listener.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using TemuKJD.UserComponent;
|
||||
|
||||
internal static class NumericRangeSmoke
|
||||
{
|
||||
[STAThread]
|
||||
public static void Main()
|
||||
{
|
||||
using (var range = new UcNumericRange())
|
||||
{
|
||||
int width = range.Width;
|
||||
var layout = (TableLayoutPanel)range.Controls[0];
|
||||
var separator = (Label)layout.GetControlFromPosition(1, 0);
|
||||
var margin = separator.Margin;
|
||||
var cell = layout.GetControlFromPosition(0, 0);
|
||||
var editor = (NumericUpDown)cell.Controls[0];
|
||||
var text = (TextBox)(editor.Controls[0] is TextBox ? editor.Controls[0] : editor.Controls[1]);
|
||||
var buttons = editor.Controls[0] == text ? editor.Controls[1] : editor.Controls[0];
|
||||
range.SeparatorText = "~";
|
||||
range.Compact = true;
|
||||
var rightCell = layout.GetControlFromPosition(2, 0);
|
||||
using (var bitmap = new Bitmap(range.Width, range.Height))
|
||||
{
|
||||
range.DrawToBitmap(bitmap, range.ClientRectangle);
|
||||
int y = rightCell.Top + rightCell.Height / 2;
|
||||
int border = bitmap.GetPixel(rightCell.Right - 1, y).ToArgb();
|
||||
if (border == editor.BackColor.ToArgb() || border != bitmap.GetPixel(rightCell.Left, y).ToArgb())
|
||||
throw new Exception("结束值输入框右边框未绘制");
|
||||
}
|
||||
if (range.Width != 112 || buttons.Left < cell.Width - 2 || text.Right < cell.Width - 4)
|
||||
throw new Exception("紧凑模式未充分利用输入区域");
|
||||
if (separator.Text != "~" || range.Width >= width || separator.Margin != Padding.Empty)
|
||||
throw new Exception("紧凑布局或分隔文字错误");
|
||||
range.Compact = false;
|
||||
if (buttons.Right > cell.Width || text.Right > buttons.Left) throw new Exception("微调按钮未恢复");
|
||||
if (range.Width != width || separator.Margin != margin)
|
||||
throw new Exception("普通布局未恢复");
|
||||
range.Width = 190;
|
||||
range.Compact = true;
|
||||
if (range.Width != 190) throw new Exception("自定义宽度被覆盖");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user