Files
ColaFlow/colaflow-api/tests/Modules/Mcp/ColaFlow.Modules.Mcp.Tests/Services/ResourceDiscoveryServiceTests.cs
Yaojia Wang 3ab505e0f6 feat(backend): Implement Story 5.6 - Resource Registration & Discovery
Implemented pluggable resource registration and auto-discovery mechanism for MCP Resources.

Changes:
- Enhanced McpResourceDescriptor with metadata (Category, Version, Parameters, Examples, Tags, IsEnabled)
- Created ResourceDiscoveryService for Assembly scanning and auto-discovery
- Updated McpResourceRegistry with category support and grouping methods
- Enhanced ResourcesListMethodHandler to return categorized resources with full metadata
- Created ResourceHealthCheckHandler for resource availability verification
- Updated all existing Resources (Projects, Issues, Sprints, Users) with Categories and Versions
- Updated McpServiceExtensions to use auto-discovery at startup
- Added comprehensive unit tests for discovery and health check

Features:
 New Resources automatically discovered via Assembly scanning
 Resources organized by category (Projects, Issues, Sprints, Users)
 Rich metadata for documentation (parameters, examples, tags)
 Health check endpoint (resources/health) for monitoring
 Thread-safe registry operations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 16:07:50 +01:00

73 lines
2.2 KiB
C#

using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Contracts.Resources;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
namespace ColaFlow.Modules.Mcp.Tests.Services;
public class ResourceDiscoveryServiceTests
{
private readonly IResourceDiscoveryService _discoveryService;
private readonly ILogger<ResourceDiscoveryService> _mockLogger;
public ResourceDiscoveryServiceTests()
{
_mockLogger = Substitute.For<ILogger<ResourceDiscoveryService>>();
_discoveryService = new ResourceDiscoveryService(_mockLogger);
}
[Fact]
public void DiscoverResourceTypes_ShouldFindAllResourceImplementations()
{
// Act
var resourceTypes = _discoveryService.DiscoverResourceTypes();
// Assert
resourceTypes.Should().NotBeEmpty();
resourceTypes.Should().AllSatisfy(type =>
{
typeof(IMcpResource).IsAssignableFrom(type).Should().BeTrue();
type.IsInterface.Should().BeFalse();
type.IsAbstract.Should().BeFalse();
});
}
[Fact]
public void DiscoverResourceTypes_ShouldFindKnownResources()
{
// Act
var resourceTypes = _discoveryService.DiscoverResourceTypes();
// Assert - should find at least these known resources
var typeNames = resourceTypes.Select(t => t.Name).ToList();
typeNames.Should().Contain("ProjectsListResource");
typeNames.Should().Contain("ProjectsGetResource");
typeNames.Should().Contain("IssuesSearchResource");
typeNames.Should().Contain("IssuesGetResource");
typeNames.Should().Contain("SprintsCurrentResource");
typeNames.Should().Contain("UsersListResource");
}
[Fact]
public void DiscoverResourceTypes_ShouldNotIncludeInterfaces()
{
// Act
var resourceTypes = _discoveryService.DiscoverResourceTypes();
// Assert
resourceTypes.Should().NotContain(t => t.IsInterface);
}
[Fact]
public void DiscoverResourceTypes_ShouldNotIncludeAbstractClasses()
{
// Act
var resourceTypes = _discoveryService.DiscoverResourceTypes();
// Assert
resourceTypes.Should().NotContain(t => t.IsAbstract);
}
}