| 1 | using AgentForge.Abstractions; |
| 2 | using AgentForge.Plugins; |
| 3 | |
| 4 | namespace AgentForge.Tests; |
| 5 | |
| 6 | public sealed class ForgePluginHostSettingsTests |
| 7 | { |
| 8 | [Fact] |
| 9 | public void LoadToml_parses_plugins_host_section_and_catalog_entries() |
| 10 | { |
| 11 | const string toml = """ |
| 12 | active_bundle = "standard" |
| 13 | |
| 14 | [plugins] |
| 15 | discovery = "auto" |
| 16 | |
| 17 | [plugins.auto] |
| 18 | exclude = ["ci-runner-local"] |
| 19 | require_manifest_entry = true |
| 20 | |
| 21 | [plugins.marketplace] |
| 22 | registry_url = "https://registry.example/v1" |
| 23 | cache_path = "/data/plugin-registry" |
| 24 | |
| 25 | [plugins.view-shell] |
| 26 | assembly = "AgentForge.Plugin.ViewShell.dll" |
| 27 | tier = "core" |
| 28 | """; |
| 29 | |
| 30 | var manifest = ForgePluginManifestLoader.LoadTomlText(toml); |
| 31 | |
| 32 | Assert.Equal(ForgePluginDiscovery.Auto, manifest.Host.Discovery); |
| 33 | Assert.Equal(["ci-runner-local"], manifest.Host.Auto.Exclude); |
| 34 | Assert.True(manifest.Host.Auto.RequireManifestEntry); |
| 35 | Assert.Equal("https://registry.example/v1", manifest.Host.Marketplace.RegistryUrl); |
| 36 | Assert.Equal("/data/plugin-registry", manifest.Host.Marketplace.CachePath); |
| 37 | Assert.True(manifest.Plugins.ContainsKey("view-shell")); |
| 38 | Assert.Equal("core", manifest.Plugins["view-shell"].Tier); |
| 39 | Assert.False(manifest.Plugins.ContainsKey("marketplace")); |
| 40 | Assert.False(manifest.Plugins.ContainsKey("auto")); |
| 41 | } |
| 42 | |
| 43 | [Fact] |
| 44 | public void FORGE_PLUGIN_DISCOVERY_env_overrides_manifest() |
| 45 | { |
| 46 | const string toml = """ |
| 47 | [plugins] |
| 48 | discovery = "manual" |
| 49 | """; |
| 50 | |
| 51 | var manifest = ForgePluginManifestLoader.LoadTomlText(toml); |
| 52 | Environment.SetEnvironmentVariable("FORGE_PLUGIN_DISCOVERY", "auto"); |
| 53 | try |
| 54 | { |
| 55 | ForgePluginLoader.ApplyPluginDiscoveryEnvironmentOverride(manifest); |
| 56 | Assert.Equal(ForgePluginDiscovery.Auto, manifest.Host.Discovery); |
| 57 | } |
| 58 | finally |
| 59 | { |
| 60 | Environment.SetEnvironmentVariable("FORGE_PLUGIN_DISCOVERY", null); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | [Fact] |
| 65 | public void Auto_discovery_loads_bundled_plugins_from_test_output() |
| 66 | { |
| 67 | var pluginsDir = Path.Combine(AppContext.BaseDirectory, "plugins"); |
| 68 | if (!Directory.Exists(pluginsDir)) |
| 69 | { |
| 70 | // Test output may not copy all plugin DLLs in CI slices. |
| 71 | return; |
| 72 | } |
| 73 | |
| 74 | var manifest = new ForgePluginManifest |
| 75 | { |
| 76 | Host = new ForgePluginHostSettings { Discovery = ForgePluginDiscovery.Auto }, |
| 77 | }; |
| 78 | |
| 79 | var discovered = ForgePluginLoader.DiscoverPlugins(manifest, pluginsDir); |
| 80 | Assert.NotEmpty(discovered); |
| 81 | Assert.Contains(discovered, item => string.Equals(item.Id, "issue", StringComparison.OrdinalIgnoreCase)); |
| 82 | } |
| 83 | } |
| 84 | |