stop using shared dir
This commit is contained in:
parent
3c8ff5a547
commit
5cc3d9d526
6 changed files with 26 additions and 26 deletions
65
test/mcp/configuration_test.rb
Normal file
65
test/mcp/configuration_test.rb
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
module MCP
|
||||
class ConfigurationTest < ActiveSupport::TestCase
|
||||
test "initializes with a default no-op exception reporter" do
|
||||
config = Configuration.new
|
||||
assert_respond_to config, :exception_reporter
|
||||
|
||||
# The default reporter should be callable but do nothing
|
||||
exception = StandardError.new("test error")
|
||||
server_context = { test: "context" }
|
||||
|
||||
# Should not raise any errors
|
||||
config.exception_reporter.call(exception, server_context)
|
||||
end
|
||||
|
||||
test "allows setting a custom exception reporter" do
|
||||
config = Configuration.new
|
||||
reported_exception = nil
|
||||
reported_context = nil
|
||||
|
||||
config.exception_reporter = ->(exception, server_context) do
|
||||
reported_exception = exception
|
||||
reported_context = server_context
|
||||
end
|
||||
|
||||
test_exception = StandardError.new("test error")
|
||||
test_context = { foo: "bar" }
|
||||
|
||||
config.exception_reporter.call(test_exception, test_context)
|
||||
|
||||
assert_equal test_exception, reported_exception
|
||||
assert_equal test_context, reported_context
|
||||
end
|
||||
|
||||
test "initializes with default protocol version" do
|
||||
config = Configuration.new
|
||||
assert_equal Configuration::DEFAULT_PROTOCOL_VERSION, config.protocol_version
|
||||
end
|
||||
|
||||
test "allows setting a custom protocol version" do
|
||||
config = Configuration.new
|
||||
custom_version = "2025-03-27"
|
||||
config.protocol_version = custom_version
|
||||
assert_equal custom_version, config.protocol_version
|
||||
end
|
||||
|
||||
test "merges protocol version from other configuration" do
|
||||
config1 = Configuration.new(protocol_version: "2025-03-27")
|
||||
config2 = Configuration.new(protocol_version: "2025-03-28")
|
||||
config3 = Configuration.new
|
||||
|
||||
merged = config1.merge(config2)
|
||||
assert_equal "2025-03-28", merged.protocol_version
|
||||
|
||||
merged = config1.merge(config3)
|
||||
assert_equal "2025-03-27", merged.protocol_version
|
||||
|
||||
merged = config3.merge(config1)
|
||||
assert_equal "2025-03-27", merged.protocol_version
|
||||
end
|
||||
end
|
||||
end
|
||||
63
test/mcp/instrumentation_test.rb
Normal file
63
test/mcp/instrumentation_test.rb
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
module MCP
|
||||
class InstrumentationTest < ActiveSupport::TestCase
|
||||
class Subject
|
||||
include Instrumentation
|
||||
attr_reader :instrumentation_data_received, :configuration
|
||||
|
||||
def initialize
|
||||
@configuration = MCP::Configuration.new
|
||||
@configuration.instrumentation_callback = ->(data) { @instrumentation_data_received = data }
|
||||
end
|
||||
|
||||
def instrumented_method
|
||||
instrument_call("instrumented_method") do
|
||||
# nothing to do
|
||||
end
|
||||
end
|
||||
|
||||
def instrumented_method_with_additional_data
|
||||
instrument_call("instrumented_method_with_additional_data") do
|
||||
add_instrumentation_data(additional_data: "test")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "#instrument_call adds the method name to the instrumentation data" do
|
||||
subject = Subject.new
|
||||
|
||||
subject.instrumented_method
|
||||
assert_equal({ method: "instrumented_method" }, subject.instrumentation_data_received.tap do |data|
|
||||
data.delete(:duration)
|
||||
end)
|
||||
end
|
||||
|
||||
test "#instrument_call exposes data added via add_instrumentation_data" do
|
||||
subject = Subject.new
|
||||
|
||||
subject.instrumented_method_with_additional_data
|
||||
assert_equal(
|
||||
{ method: "instrumented_method_with_additional_data", additional_data: "test" },
|
||||
subject.instrumentation_data_received.tap { |data| data.delete(:duration) },
|
||||
)
|
||||
end
|
||||
|
||||
test "#instrument_call resets the instrumentation data between calls" do
|
||||
subject = Subject.new
|
||||
|
||||
subject.instrumented_method_with_additional_data
|
||||
assert_equal(
|
||||
{ method: "instrumented_method_with_additional_data", additional_data: "test" },
|
||||
subject.instrumentation_data_received.tap { |data| data.delete(:duration) },
|
||||
)
|
||||
|
||||
subject.instrumented_method
|
||||
assert_equal({ method: "instrumented_method" }, subject.instrumentation_data_received.tap do |data|
|
||||
data.delete(:duration)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
75
test/mcp/methods_test.rb
Normal file
75
test/mcp/methods_test.rb
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
module MCP
|
||||
class MethodsTest < ActiveSupport::TestCase
|
||||
test "ensure_capability! for tools/list method raises an error if tools capability is not present" do
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(Methods::TOOLS_LIST, {})
|
||||
end
|
||||
assert_equal "Server does not support tools (required for tools/list)", error.message
|
||||
end
|
||||
|
||||
test "ensure_capability! for sampling/createMessage raises an error if sampling capability is not present" do
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(Methods::SAMPLING_CREATE_MESSAGE, {})
|
||||
end
|
||||
assert_equal "Server does not support sampling (required for sampling/createMessage)", error.message
|
||||
end
|
||||
|
||||
test "ensure_capability! for completion/complete raises an error if completions capability is not present" do
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(Methods::COMPLETION_COMPLETE, {})
|
||||
end
|
||||
assert_equal "Server does not support completions (required for completion/complete)", error.message
|
||||
end
|
||||
|
||||
test "ensure_capability! for logging/setLevel raises an error if logging capability is not present" do
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(Methods::LOGGING_SET_LEVEL, {})
|
||||
end
|
||||
assert_equal "Server does not support logging (required for logging/setLevel)", error.message
|
||||
end
|
||||
|
||||
test "ensure_capability! for prompts/get and prompts/list raise an error if prompts capability is not present" do
|
||||
[Methods::PROMPTS_GET, Methods::PROMPTS_LIST].each do |method|
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(method, {})
|
||||
end
|
||||
assert_equal "Server does not support prompts (required for #{method})", error.message
|
||||
end
|
||||
end
|
||||
|
||||
test "ensure_capability! for resources/list, resources/templates/list, resources/read raise an error if resources capability is not present" do
|
||||
[Methods::RESOURCES_LIST, Methods::RESOURCES_TEMPLATES_LIST, Methods::RESOURCES_READ].each do |method|
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(method, {})
|
||||
end
|
||||
assert_equal "Server does not support resources (required for #{method})", error.message
|
||||
end
|
||||
end
|
||||
|
||||
test "ensure_capability! for tools/call and tools/list raise an error if tools capability is not present" do
|
||||
[Methods::TOOLS_CALL, Methods::TOOLS_LIST].each do |method|
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(method, {})
|
||||
end
|
||||
assert_equal "Server does not support tools (required for #{method})", error.message
|
||||
end
|
||||
end
|
||||
|
||||
test "ensure_capability! for resources/subscribe raises an error if resources subscribe capability is not present" do
|
||||
error = assert_raises(Methods::MissingRequiredCapabilityError) do
|
||||
Methods.ensure_capability!(Methods::RESOURCES_SUBSCRIBE, { resources: {} })
|
||||
end
|
||||
assert_equal "Server does not support resources_subscribe (required for resources/subscribe)", error.message
|
||||
end
|
||||
|
||||
test "ensure_capability! does not raise for ping and initialize methods" do
|
||||
assert_nothing_raised { Methods.ensure_capability!(Methods::PING, {}) }
|
||||
assert_nothing_raised { Methods.ensure_capability!(Methods::INITIALIZE, {}) }
|
||||
end
|
||||
end
|
||||
end
|
||||
146
test/mcp/prompt_test.rb
Normal file
146
test/mcp/prompt_test.rb
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
module MCP
|
||||
class PromptTest < ActiveSupport::TestCase
|
||||
class TestPrompt < Prompt
|
||||
description "Test prompt"
|
||||
arguments [
|
||||
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
||||
]
|
||||
|
||||
class << self
|
||||
def template(args, server_context:)
|
||||
Prompt::Result.new(
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
Prompt::Message.new(role: "user", content: Content::Text.new("Hello, world!")),
|
||||
Prompt::Message.new(role: "assistant", content: Content::Text.new("Hello, friend!")),
|
||||
],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "#template returns a Result with description and messages" do
|
||||
prompt = TestPrompt
|
||||
|
||||
expected_template_result = {
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
{ role: "user", content: { text: "Hello, world!", type: "text" } },
|
||||
{ role: "assistant", content: { text: "Hello, friend!", type: "text" } },
|
||||
],
|
||||
}
|
||||
|
||||
result = prompt.template({ "test_argument" => "Hello, friend!" }, server_context: { user_id: 123 })
|
||||
|
||||
assert_equal expected_template_result, result.to_h
|
||||
end
|
||||
|
||||
test "allows declarative definition of prompts as classes" do
|
||||
class MockPrompt < Prompt
|
||||
prompt_name "my_mock_prompt"
|
||||
description "a mock prompt for testing"
|
||||
arguments [
|
||||
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
||||
]
|
||||
|
||||
class << self
|
||||
def template(args, server_context:)
|
||||
Prompt::Result.new(
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
Prompt::Message.new(role: "user", content: Content::Text.new("Hello, world!")),
|
||||
Prompt::Message.new(role: "assistant", content: Content::Text.new(args["test_argument"])),
|
||||
],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
prompt = MockPrompt
|
||||
|
||||
assert_equal "my_mock_prompt", prompt.name_value
|
||||
assert_equal "a mock prompt for testing", prompt.description
|
||||
assert_equal "test_argument", prompt.arguments.first.name
|
||||
assert_equal "Test argument", prompt.arguments.first.description
|
||||
assert prompt.arguments.first.required
|
||||
|
||||
expected_template_result = {
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
{ role: "user", content: { text: "Hello, world!", type: "text" } },
|
||||
{ role: "assistant", content: { text: "Hello, friend!", type: "text" } },
|
||||
],
|
||||
}
|
||||
|
||||
result = prompt.template({ "test_argument" => "Hello, friend!" }, server_context: { user_id: 123 })
|
||||
assert_equal expected_template_result, result.to_h
|
||||
end
|
||||
|
||||
test "defaults to class name as prompt name" do
|
||||
class DefaultNamePrompt < Prompt
|
||||
description "a mock prompt for testing"
|
||||
arguments [
|
||||
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
||||
]
|
||||
|
||||
class << self
|
||||
def template(args, server_context:)
|
||||
Prompt::Result.new(
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
Prompt::Message.new(role: "user", content: Content::Text.new("Hello, world!")),
|
||||
Prompt::Message.new(role: "assistant", content: Content::Text.new(args["test_argument"])),
|
||||
],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
prompt = DefaultNamePrompt
|
||||
|
||||
assert_equal "default_name_prompt", prompt.name_value
|
||||
assert_equal "a mock prompt for testing", prompt.description
|
||||
assert_equal "test_argument", prompt.arguments.first.name
|
||||
end
|
||||
|
||||
test ".define allows definition of simple prompts with a block" do
|
||||
prompt = Prompt.define(
|
||||
name: "mock_prompt",
|
||||
description: "a mock prompt for testing",
|
||||
arguments: [
|
||||
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
||||
],
|
||||
) do |args, server_context:|
|
||||
content = Content::Text.new(args["test_argument"] + " user: #{server_context[:user_id]}")
|
||||
|
||||
Prompt::Result.new(
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
Prompt::Message.new(role: "user", content: Content::Text.new("Hello, world!")),
|
||||
Prompt::Message.new(role: "assistant", content:),
|
||||
],
|
||||
)
|
||||
end
|
||||
|
||||
assert_equal "mock_prompt", prompt.name_value
|
||||
assert_equal "a mock prompt for testing", prompt.description
|
||||
assert_equal "test_argument", prompt.arguments.first.name
|
||||
|
||||
expected = {
|
||||
description: "Hello, world!",
|
||||
messages: [
|
||||
{ role: "user", content: { text: "Hello, world!", type: "text" } },
|
||||
{ role: "assistant", content: { text: "Hello, friend! user: 123", type: "text" } },
|
||||
],
|
||||
}
|
||||
|
||||
result = prompt.template({ "test_argument" => "Hello, friend!" }, server_context: { user_id: 123 })
|
||||
assert_equal expected, result.to_h
|
||||
end
|
||||
end
|
||||
end
|
||||
22
test/mcp/string_utils_test.rb
Normal file
22
test/mcp/string_utils_test.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
module MCP
|
||||
class StringUtilsTest < Minitest::Test
|
||||
def test_handle_from_class_name_returns_the_class_name_without_the_module_for_a_class_without_a_module
|
||||
assert_equal("test", StringUtils.handle_from_class_name("Test"))
|
||||
assert_equal("test_class", StringUtils.handle_from_class_name("TestClass"))
|
||||
end
|
||||
|
||||
def test_handle_from_class_name_returns_the_class_name_without_the_module_for_a_class_with_a_single_parent_module
|
||||
assert_equal("test", StringUtils.handle_from_class_name("Module::Test"))
|
||||
assert_equal("test_class", StringUtils.handle_from_class_name("Module::TestClass"))
|
||||
end
|
||||
|
||||
def test_handle_from_class_name_returns_the_class_name_without_the_module_for_a_class_with_multiple_parent_modules
|
||||
assert_equal("test", StringUtils.handle_from_class_name("Module::Submodule::Test"))
|
||||
assert_equal("test_class", StringUtils.handle_from_class_name("Module::Submodule::TestClass"))
|
||||
end
|
||||
end
|
||||
end
|
||||
32
test/mcp/tool/input_schema_test.rb
Normal file
32
test/mcp/tool/input_schema_test.rb
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "test_helper"
|
||||
|
||||
module MCP
|
||||
class Tool
|
||||
class InputSchemaTest < ActiveSupport::TestCase
|
||||
test "required arguments are converted to symbols" do
|
||||
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: ["message"])
|
||||
assert_equal [:message], input_schema.required
|
||||
end
|
||||
|
||||
test "to_h returns a hash representation of the input schema" do
|
||||
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: [:message])
|
||||
assert_equal(
|
||||
{ type: "object", properties: { message: { type: "string" } }, required: [:message] },
|
||||
input_schema.to_h,
|
||||
)
|
||||
end
|
||||
|
||||
test "missing_required_arguments returns an array of missing required arguments" do
|
||||
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: [:message])
|
||||
assert_equal [:message], input_schema.missing_required_arguments({})
|
||||
end
|
||||
|
||||
test "missing_required_arguments returns an empty array if no required arguments are missing" do
|
||||
input_schema = InputSchema.new(properties: { message: { type: "string" } }, required: [:message])
|
||||
assert_empty input_schema.missing_required_arguments({ message: "Hello, world!" })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue