Skip to content

Commit

Permalink
fix list proxy not showing artifacts w no res
Browse files Browse the repository at this point in the history
  • Loading branch information
riina committed Mar 3, 2023
1 parent e482a4c commit ac4f6d9
Show file tree
Hide file tree
Showing 7 changed files with 328 additions and 16 deletions.
92 changes: 92 additions & 0 deletions src/Art.Common.Tests/ArtifactToolDumpProxyTests.cs
@@ -0,0 +1,92 @@
using System.Text.Json;
using Art.Common.Management;
using Art.Common.Proxies;
using Art.TestsBase;
using NUnit.Framework;

namespace Art.Common.Tests;

public class ArtifactToolDumpProxyTests
{
[Test]
public async Task FindOnlyTool_WithoutArtifactList_Throws()
{
var profile = new ArtifactToolProfile("tool", null, null);
var tool = new ProgrammableArtifactFindTool((v, k) =>
{
int i = int.Parse(k);
if (1 <= i && i <= 3)
{
return v.CreateData($"{i}");
}
return null;
});
await tool.InitializeAsync(profile: profile);
var proxy = new ArtifactToolDumpProxy(tool, new ArtifactToolDumpOptions(), null);
Assert.That(async () => await proxy.DumpAsync(), Throws.InstanceOf<NotSupportedException>());
}

[Test]
public async Task FindOnlyTool_WithArtifactList_Success()
{
var options = new Dictionary<string, JsonElement> { { "artifactList", JsonSerializer.SerializeToElement(new[] { "1", "2", "3" }) } };
var profile = new ArtifactToolProfile("tool", null, options);
var arm = new InMemoryArtifactRegistrationManager();
var config = new ArtifactToolConfig(arm, new NullArtifactDataManager());
var tool = new ProgrammableArtifactFindTool((v, k) =>
{
int i = int.Parse(k);
if (1 <= i && i <= 3)
{
return v.CreateData($"{i}");
}
return null;
});
await tool.InitializeAsync(config: config, profile: profile);
var proxy = new ArtifactToolDumpProxy(tool, new ArtifactToolDumpOptions(), null);
await proxy.DumpAsync();
Assert.That((await arm.ListArtifactsAsync()).Select(v => int.Parse(v.Key.Id)), Is.EquivalentTo(new[] { 1, 2, 3 }));
}

[Test]
public async Task DumpOnlyTool_WithoutArtifactList_Success()
{
var options = new Dictionary<string, JsonElement> { { "artifactList", JsonSerializer.SerializeToElement(new[] { "1", "2", "3" }) } };
var profile = new ArtifactToolProfile("tool", null, options);
var arm = new InMemoryArtifactRegistrationManager();
var config = new ArtifactToolConfig(arm, new NullArtifactDataManager());
var tool = new AsyncProgrammableArtifactDumpTool(async v =>
{
for (int i = 1; i <= 3; i++)
{
await v.DumpArtifactAsync(v.CreateData($"{i}"));
}
});
await tool.InitializeAsync(config: config, profile: profile);
var proxy = new ArtifactToolDumpProxy(tool, new ArtifactToolDumpOptions(), null);
await proxy.DumpAsync();
Assert.That((await arm.ListArtifactsAsync()).Select(v => int.Parse(v.Key.Id)), Is.EquivalentTo(new[] { 1, 2, 3 }));
}

[Test]
public async Task DumpOnlyTool_WithArtifactList_DoesNotFilter()
{
var options = new Dictionary<string, JsonElement> { { "artifactList", JsonSerializer.SerializeToElement(new[] { "1", "2" }) } };
var profile = new ArtifactToolProfile("tool", null, options);
var arm = new InMemoryArtifactRegistrationManager();
var config = new ArtifactToolConfig(arm, new NullArtifactDataManager());
var tool = new AsyncProgrammableArtifactDumpTool(async v =>
{
for (int i = 1; i <= 3; i++)
{
await v.DumpArtifactAsync(v.CreateData($"{i}"));
}
});
await tool.InitializeAsync(config: config, profile: profile);
var proxy = new ArtifactToolDumpProxy(tool, new ArtifactToolDumpOptions(), null);
await proxy.DumpAsync();
Assert.That((await arm.ListArtifactsAsync()).Select(v => int.Parse(v.Key.Id)), Is.EquivalentTo(new[] { 1, 2, 3 }));
}

// TODO prioritisation tests
}
84 changes: 84 additions & 0 deletions src/Art.Common.Tests/ArtifactToolListProxyTests.cs
@@ -0,0 +1,84 @@
using System.Text.Json;
using Art.Common.Proxies;
using Art.TestsBase;
using NUnit.Framework;

namespace Art.Common.Tests;

public class ArtifactToolListProxyTests
{
[Test]
public async Task FindOnlyTool_WithoutArtifactList_Throws()
{
var profile = new ArtifactToolProfile("tool", null, null);
var tool = new ProgrammableArtifactFindTool((v, k) =>
{
int i = int.Parse(k);
if (1 <= i && i <= 3)
{
return v.CreateData($"{i}");
}
return null;
});
await tool.InitializeAsync(profile: profile);
var proxy = new ArtifactToolListProxy(tool, new ArtifactToolListOptions(), null);
Assert.That(async () => await proxy.ListAsync().ToListAsync(), Throws.InstanceOf<NotSupportedException>());
}

[Test]
public async Task FindOnlyTool_WithArtifactList_Success()
{
var options = new Dictionary<string, JsonElement> { { "artifactList", JsonSerializer.SerializeToElement(new[] { "1", "2", "3" }) } };
var profile = new ArtifactToolProfile("tool", null, options);
var tool = new ProgrammableArtifactFindTool((v, k) =>
{
int i = int.Parse(k);
if (1 <= i && i <= 3)
{
return v.CreateData($"{i}");
}
return null;
});
await tool.InitializeAsync(profile: profile);
var proxy = new ArtifactToolListProxy(tool, new ArtifactToolListOptions(), null);
var results = await proxy.ListAsync().ToListAsync();
Assert.That(results.Select(v => int.Parse(v.Info.Key.Id)), Is.EquivalentTo(new[] { 1, 2, 3 }));
}

[Test]
public async Task DumpOnlyTool_WithoutArtifactList_Success()
{
var profile = new ArtifactToolProfile("tool", null, null);
var tool = new AsyncProgrammableArtifactDumpTool(async v =>
{
for (int i = 1; i <= 3; i++)
{
await v.DumpArtifactAsync(v.CreateData($"{i}"));
}
});
await tool.InitializeAsync(profile: profile);
var proxy = new ArtifactToolListProxy(tool, new ArtifactToolListOptions(), null);
var results = await proxy.ListAsync().ToListAsync();
Assert.That(results.Select(v => int.Parse(v.Info.Key.Id)), Is.EquivalentTo(new[] { 1, 2, 3 }));
}

[Test]
public async Task DumpOnlyTool_WithArtifactList_DoesNotFilter()
{
var options = new Dictionary<string, JsonElement> { { "artifactList", JsonSerializer.SerializeToElement(new[] { "1", "2" }) } };
var profile = new ArtifactToolProfile("tool", null, options);
var tool = new AsyncProgrammableArtifactDumpTool(async v =>
{
for (int i = 1; i <= 3; i++)
{
await v.DumpArtifactAsync(v.CreateData($"{i}"));
}
});
await tool.InitializeAsync(profile: profile);
var proxy = new ArtifactToolListProxy(tool, new ArtifactToolListOptions(), null);
var results = await proxy.ListAsync().ToListAsync();
Assert.That(results.Select(v => int.Parse(v.Info.Key.Id)), Is.EquivalentTo(new[] { 1, 2, 3 }));
}

// TODO prioritisation tests
}
1 change: 1 addition & 0 deletions src/Art.Common/Proxies/ArtifactToolDumpProxy.cs
Expand Up @@ -51,6 +51,7 @@ private static void Validate(ArtifactToolDumpOptions options, bool constructor)
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="InvalidOperationException">Thrown when an invalid configuration is detected.</exception>
/// <exception cref="NotSupportedException">Thrown when a tool does not natively and cannot be made to support dumping.</exception>
public async ValueTask DumpAsync(CancellationToken cancellationToken = default)
{
if (ArtifactTool == null) throw new InvalidOperationException("Artifact tool cannot be null");
Expand Down
33 changes: 27 additions & 6 deletions src/Art.Common/Proxies/ArtifactToolListProxy.cs
Expand Up @@ -44,6 +44,7 @@ public ArtifactToolListProxy(IArtifactTool artifactTool, ArtifactToolListOptions
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Async-enumerable artifacts.</returns>
/// <exception cref="InvalidOperationException">Thrown when an invalid configuration is detected.</exception>
/// <exception cref="NotSupportedException">Thrown when a tool does not natively and cannot be made to support listing.</exception>
public async IAsyncEnumerable<IArtifactData> ListAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (ArtifactTool == null) throw new InvalidOperationException("Artifact tool cannot be null");
Expand Down Expand Up @@ -87,23 +88,43 @@ await foreach (IArtifactData data in enumerable.ConfigureAwait(false))
}
if (artifactTool is IArtifactDumpTool dumpTool)
{
IArtifactDataManager previous = artifactTool.DataManager;
IArtifactDataManager previousAdm = artifactTool.DataManager;
IArtifactRegistrationManager previousArm = artifactTool.RegistrationManager;
try
{
InMemoryArtifactDataManager im = new();
artifactTool.DataManager = im;
InMemoryArtifactDataManager adm = new();
InMemoryArtifactRegistrationManager arm = new();
artifactTool.DataManager = adm;
artifactTool.RegistrationManager = arm;
await dumpTool.DumpAsync(cancellationToken).ConfigureAwait(false);
foreach ((ArtifactKey ak, List<ArtifactResourceInfo> resources) in im.Artifacts)
HashSet<ArtifactKey> known = new();
foreach ((ArtifactKey ak, List<ArtifactResourceInfo> resources) in adm.Artifacts)
{
if (await artifactTool.RegistrationManager.TryGetArtifactAsync(ak, cancellationToken).ConfigureAwait(false) is not { } info) continue;
if (await artifactTool.RegistrationManager.TryGetArtifactAsync(ak, cancellationToken).ConfigureAwait(false) is not { } info)
{
continue;
}
if (!known.Add(ak))
{
continue;
}
ArtifactData data = new(info);
data.AddRange(resources);
yield return data;
}
foreach (var info in await arm.ListArtifactsAsync(cancellationToken).ConfigureAwait(false))
{
if (!known.Add(info.Key))
{
continue;
}
yield return new ArtifactData(info);
}
}
finally
{
artifactTool.DataManager = previous;
artifactTool.DataManager = previousAdm;
artifactTool.RegistrationManager = previousArm;
}
yield break;
}
Expand Down
38 changes: 38 additions & 0 deletions src/Art.TestsBase/ProgrammableArtifactDumpTool.cs
Expand Up @@ -40,3 +40,41 @@ private record CustomArtifactToolRegistryEntry(ArtifactToolID Id, SynchronousDum
public override Type GetArtifactToolType() => typeof(ProgrammableArtifactDumpTool);
}
}

public class AsyncProgrammableArtifactDumpTool : ArtifactTool, IArtifactDumpTool
{
public delegate Task AsyncDumpDelegate(AsyncProgrammableArtifactDumpTool tool);

public readonly AsyncDumpDelegate? AsyncDumpAction;

public AsyncProgrammableArtifactDumpTool(AsyncDumpDelegate asyncDumpAction)
{
AsyncDumpAction = asyncDumpAction;
}

public Task DumpAsync(CancellationToken cancellationToken = default)
{
if (AsyncDumpAction != null)
{
return AsyncDumpAction(this);
}
throw new NotImplementedException();
}

public static ArtifactToolRegistryEntry CreateRegistryEntry(AsyncDumpDelegate asyncDumpDelegate)
{
return CreateRegistryEntry(ArtifactToolIDUtil.CreateToolId<AsyncProgrammableArtifactDumpTool>(), asyncDumpDelegate);
}

public static ArtifactToolRegistryEntry CreateRegistryEntry(ArtifactToolID artifactToolId, AsyncDumpDelegate asyncDumpDelegate)
{
return new CustomArtifactToolRegistryEntry(artifactToolId, asyncDumpDelegate);
}

private record CustomArtifactToolRegistryEntry(ArtifactToolID Id, AsyncDumpDelegate AsyncDumpDelegate) : ArtifactToolRegistryEntry(Id)
{
public override IArtifactTool CreateArtifactTool() => new AsyncProgrammableArtifactDumpTool(AsyncDumpDelegate);

public override Type GetArtifactToolType() => typeof(AsyncProgrammableArtifactDumpTool);
}
}
48 changes: 43 additions & 5 deletions src/Art.TestsBase/ProgrammableArtifactFindTool.cs
Expand Up @@ -6,18 +6,18 @@ public class ProgrammableArtifactFindTool : ArtifactTool, IArtifactFindTool
{
public delegate IArtifactData? SynchronousFindDelegate(ProgrammableArtifactFindTool tool, string id);

public readonly SynchronousFindDelegate? FindFunc;
public readonly SynchronousFindDelegate? SynchronousFindFunc;

public ProgrammableArtifactFindTool(SynchronousFindDelegate? findFunc)
public ProgrammableArtifactFindTool(SynchronousFindDelegate? synchronousFindFunc)
{
FindFunc = findFunc;
SynchronousFindFunc = synchronousFindFunc;
}

public Task<IArtifactData?> FindAsync(string id, CancellationToken cancellationToken = default)
{
if (FindFunc != null)
if (SynchronousFindFunc != null)
{
return Task.FromResult(FindFunc(this, id));
return Task.FromResult(SynchronousFindFunc(this, id));
}
throw new NotImplementedException();
}
Expand All @@ -39,3 +39,41 @@ private record CustomArtifactToolRegistryEntry(ArtifactToolID Id, SynchronousFin
public override Type GetArtifactToolType() => typeof(ProgrammableArtifactFindTool);
}
}

public class AsyncProgrammableArtifactFindTool : ArtifactTool, IArtifactFindTool
{
public delegate Task<IArtifactData?> AsyncFindDelegate(AsyncProgrammableArtifactFindTool tool, string id);

public readonly AsyncFindDelegate? AsyncFindFunc;

public AsyncProgrammableArtifactFindTool(AsyncFindDelegate? asyncFindFunc)
{
AsyncFindFunc = asyncFindFunc;
}

public Task<IArtifactData?> FindAsync(string id, CancellationToken cancellationToken = default)
{
if (AsyncFindFunc != null)
{
return AsyncFindFunc(this, id);
}
throw new NotImplementedException();
}

public static ArtifactToolRegistryEntry CreateRegistryEntry(AsyncFindDelegate asyncFindDelegate)
{
return CreateRegistryEntry(ArtifactToolIDUtil.CreateToolId<AsyncProgrammableArtifactFindTool>(), asyncFindDelegate);
}

public static ArtifactToolRegistryEntry CreateRegistryEntry(ArtifactToolID artifactToolId, AsyncFindDelegate asyncFindDelegate)
{
return new CustomArtifactToolRegistryEntry(artifactToolId, asyncFindDelegate);
}

private record CustomArtifactToolRegistryEntry(ArtifactToolID Id, AsyncFindDelegate AsyncFindDelegate) : ArtifactToolRegistryEntry(Id)
{
public override IArtifactTool CreateArtifactTool() => new AsyncProgrammableArtifactFindTool(AsyncFindDelegate);

public override Type GetArtifactToolType() => typeof(AsyncProgrammableArtifactFindTool);
}
}

0 comments on commit ac4f6d9

Please sign in to comment.