using System.Text.Json;
using System.Text.Json.Nodes;
using XFEExtension.NetCore.XUnit.Assertions;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEWorkflow.Abstractions;
using XFEWorkflow.Infrastructure.Compilation;
using XFEWorkflow.Infrastructure.Execution;
using XFEWorkflow.Infrastructure.Plugins;
using XFEWorkflow.Infrastructure.Storage;
using XFEWorkflow.Plugins.WeCom;
namespace XFEWorkflow.Test;
[TestFixture]
public sealed class WeComContactSampleTests
{
[Test]
public async Task JsonAndPackageImportTraverseEveryCachedContactThroughRealRunner()
{
await using var workspace = new TestWorkspace();
var plugins = new PluginManager(workspace.Paths, workspace.State);
await plugins.InstallAsync(TestSupport.Package(workspace.Paths.Temp, new WeComPlugin().Manifest));
await using var runs = new RunCoordinator(workspace.Paths, plugins, new CredentialVault(workspace.State), new(),
TestSupport.FindOutput("XFEWorkflow.Runner", "XFEWorkflow.Runner.exe"));
var repository = new WorkflowRepository(workspace.Paths); var calls = 0;
var contacts = JsonNode.Parse("""[{"id":"1001","displayName":"张三","note":" 原始内容\n换行 😀 ","extra":{"$var":"不要解析或修改"}},{"id":"1002","displayName":"李四","tags":["同事",null,2]},{"id":"1003","displayName":"王五","message":{"content":"¥var 和 $var 都是原文","quoted":{"id":"original"}}}]""")!.AsArray();
runs.Host = (_, operation, input, _) =>
{
Assert.Equal("wecom.contacts", operation); Assert.Equal("", input.String("query")); calls++;
return ValueTask.FromResult(new JsonObject { ["contacts"] = contacts.DeepClone(), ["completeRoster"] = false });
};
foreach (var extension in new[] { "json", "xfeworkflow", "generated-csharp" })
{
var source = Path.Combine(TestSupport.Root, "samples/workflows/wecom-contacts-foreach-log." + (extension == "generated-csharp" ? "json" : extension));
var workflow = await repository.ImportAsync(source);
Assert.Equal(false, workflow.Enabled); Assert.Equal("3.0.0", workflow.PluginVersions["xfe.wecom"]);
Assert.False(workflow.Id == "sample-wecom-contacts-foreach-log");
var body = workflow.Graph.Nodes.Single(x => x.CapabilityId == "core.foreach").Children["body"];
Assert.Equal(0, body.Nodes.Single(x => x.CapabilityId == "core.log").Parameters.Count);
Assert.True(body.Edges.Any(x => x.Kind == PortKind.Data && x.FromPort == "item" && x.ToPort == "message"));
Assert.False(JsonSerializer.Serialize(workflow, WorkflowJson.Options).Contains("\"$var\""));
if (extension == "generated-csharp") { GraphCodeGenerator.Update(workflow, true); workflow.Kind = WorkflowKind.CSharp; }
var run = await runs.RunAsync(workflow).WaitAsync(TimeSpan.FromSeconds(15));
Assert.Equal(RunStatus.Succeeded, run.Status, run.Error);
var logs = WorkflowLogService.RunEntries(run); Assert.Equal(3, logs.Count);
for (var i = 0; i < contacts.Count; i++)
{
var logged = JsonNode.Parse(logs[i].LogText)!;
Assert.True(JsonNode.DeepEquals(contacts[i], logged), "日志应完整保留联系人原始字段和值");
Assert.True(JsonNode.DeepEquals(contacts[i], run.Outputs["result"]![i]!["result"]));
}
Assert.False(run.Outputs.Boolean("completeRoster"));
var export = Path.Combine(workspace.Paths.Temp, "contacts-" + extension + ".xfeworkflow");
await repository.ExportAsync(workflow, export);
var restored = await repository.ImportAsync(export); Assert.Equal(workflow.Graph.Edges.Count, restored.Graph.Edges.Count);
}
Assert.Equal(3, calls);
}
[Test]
public async Task EmptyCacheProducesNoPerItemLogAndAnEmptyResult()
{
await using var workspace = new TestWorkspace(); var plugins = new PluginManager(workspace.Paths, workspace.State);
await plugins.InstallAsync(TestSupport.Package(workspace.Paths.Temp, new WeComPlugin().Manifest));
await using var runs = new RunCoordinator(workspace.Paths, plugins, new CredentialVault(workspace.State), new(),
TestSupport.FindOutput("XFEWorkflow.Runner", "XFEWorkflow.Runner.exe"));
runs.Host = (_, operation, _, _) =>
{
Assert.Equal("wecom.contacts", operation);
return ValueTask.FromResult(new JsonObject { ["contacts"] = new JsonArray(), ["completeRoster"] = false });
};
var workflow = await new WorkflowRepository(workspace.Paths).ImportAsync(Path.Combine(TestSupport.Root, "samples/workflows/wecom-contacts-foreach-log.xfeworkflow"));
var result = await runs.RunAsync(workflow).WaitAsync(TimeSpan.FromSeconds(15));
Assert.Equal(RunStatus.Succeeded, result.Status, result.Error);
Assert.Equal(0, result.Outputs["result"]!.AsArray().Count); Assert.Equal(0, WorkflowLogService.RunEntries(result).Count);
}
}
using System.Text.Json;
using System.Text.Json.Nodes;
using XFEExtension.NetCore.XUnit.Assertions;
using XFEExtension.NetCore.XUnit.Attributes;
using XFEWorkflow.Abstractions;
using XFEWorkflow.Infrastructure.Compilation;
using XFEWorkflow.Infrastructure.Execution;
using XFEWorkflow.Infrastructure.Plugins;
using XFEWorkflow.Infrastructure.Storage;
using XFEWorkflow.Plugins.WeCom;
namespace XFEWorkflow.Test;
[TestFixture]
public sealed class WeComContactSampleTests
{
[Test]
public async Task JsonAndPackageImportTraverseEveryCachedContactThroughRealRunner()
{
await using var workspace = new TestWorkspace();
var plugins = new PluginManager(workspace.Paths, workspace.State);
await plugins.InstallAsync(TestSupport.Package(workspace.Paths.Temp, new WeComPlugin().Manifest));
await using var runs = new RunCoordinator(workspace.Paths, plugins, new CredentialVault(workspace.State), new(),
TestSupport.FindOutput("XFEWorkflow.Runner", "XFEWorkflow.Runner.exe"));
var repository = new WorkflowRepository(workspace.Paths); var calls = 0;
var contacts = JsonNode.Parse("""[{"id":"1001","displayName":"张三","note":" 原始内容\n换行 😀 ","extra":{"$var":"不要解析或修改"}},{"id":"1002","displayName":"李四","tags":["同事",null,2]},{"id":"1003","displayName":"王五","message":{"content":"¥var 和 $var 都是原文","quoted":{"id":"original"}}}]""")!.AsArray();
runs.Host = (_, operation, input, _) =>
{
Assert.Equal("wecom.contacts", operation); Assert.Equal("", input.String("query")); calls++;
return ValueTask.FromResult(new JsonObject { ["contacts"] = contacts.DeepClone(), ["completeRoster"] = false });
};
foreach (var extension in new[] { "json", "xfeworkflow", "generated-csharp" })
{
var source = Path.Combine(TestSupport.Root, "samples/workflows/wecom-contacts-foreach-log." + (extension == "generated-csharp" ? "json" : extension));
var workflow = await repository.ImportAsync(source);
Assert.Equal(false, workflow.Enabled); Assert.Equal("3.0.0", workflow.PluginVersions["xfe.wecom"]);
Assert.False(workflow.Id == "sample-wecom-contacts-foreach-log");
var body = workflow.Graph.Nodes.Single(x => x.CapabilityId == "core.foreach").Children["body"];
Assert.Equal(0, body.Nodes.Single(x => x.CapabilityId == "core.log").Parameters.Count);
Assert.True(body.Edges.Any(x => x.Kind == PortKind.Data && x.FromPort == "item" && x.ToPort == "message"));
Assert.False(JsonSerializer.Serialize(workflow, WorkflowJson.Options).Contains("\"$var\""));
if (extension == "generated-csharp") { GraphCodeGenerator.Update(workflow, true); workflow.Kind = WorkflowKind.CSharp; }
var run = await runs.RunAsync(workflow).WaitAsync(TimeSpan.FromSeconds(15));
Assert.Equal(RunStatus.Succeeded, run.Status, run.Error);
var logs = WorkflowLogService.RunEntries(run); Assert.Equal(3, logs.Count);
for (var i = 0; i < contacts.Count; i++)
{
var logged = JsonNode.Parse(logs[i].LogText)!;
Assert.True(JsonNode.DeepEquals(contacts[i], logged), "日志应完整保留联系人原始字段和值");
Assert.True(JsonNode.DeepEquals(contacts[i], run.Outputs["result"]![i]!["result"]));
}
Assert.False(run.Outputs.Boolean("completeRoster"));
var export = Path.Combine(workspace.Paths.Temp, "contacts-" + extension + ".xfeworkflow");
await repository.ExportAsync(workflow, export);
var restored = await repository.ImportAsync(export); Assert.Equal(workflow.Graph.Edges.Count, restored.Graph.Edges.Count);
}
Assert.Equal(3, calls);
}
[Test]
public async Task EmptyCacheProducesNoPerItemLogAndAnEmptyResult()
{
await using var workspace = new TestWorkspace(); var plugins = new PluginManager(workspace.Paths, workspace.State);
await plugins.InstallAsync(TestSupport.Package(workspace.Paths.Temp, new WeComPlugin().Manifest));
await using var runs = new RunCoordinator(workspace.Paths, plugins, new CredentialVault(workspace.State), new(),
TestSupport.FindOutput("XFEWorkflow.Runner", "XFEWorkflow.Runner.exe"));
runs.Host = (_, operation, _, _) =>
{
Assert.Equal("wecom.contacts", operation);
return ValueTask.FromResult(new JsonObject { ["contacts"] = new JsonArray(), ["completeRoster"] = false });
};
var workflow = await new WorkflowRepository(workspace.Paths).ImportAsync(Path.Combine(TestSupport.Root, "samples/workflows/wecom-contacts-foreach-log.xfeworkflow"));
var result = await runs.RunAsync(workflow).WaitAsync(TimeSpan.FromSeconds(15));
Assert.Equal(RunStatus.Succeeded, result.Status, result.Error);
Assert.Equal(0, result.Outputs["result"]!.AsArray().Count); Assert.Equal(0, WorkflowLogService.RunEntries(result).Count);
}
}