Skip to main content
Glama
toolset_config_test.go11.4 kB
package config import ( "context" "errors" "os" "path/filepath" "testing" "github.com/BurntSushi/toml" "github.com/containers/kubernetes-mcp-server/pkg/api" "github.com/stretchr/testify/suite" ) type ToolsetConfigSuite struct { BaseConfigSuite originalToolsetConfigRegistry *extendedConfigRegistry } func (s *ToolsetConfigSuite) SetupTest() { s.originalToolsetConfigRegistry = toolsetConfigRegistry toolsetConfigRegistry = newExtendedConfigRegistry() } func (s *ToolsetConfigSuite) TearDownTest() { toolsetConfigRegistry = s.originalToolsetConfigRegistry } type ToolsetConfigForTest struct { Enabled bool `toml:"enabled"` Endpoint string `toml:"endpoint"` Timeout int `toml:"timeout"` } var _ api.ExtendedConfig = (*ToolsetConfigForTest)(nil) func (t *ToolsetConfigForTest) Validate() error { if t.Endpoint == "force-error" { return errors.New("validation error forced by test") } return nil } func toolsetConfigForTestParser(_ context.Context, primitive toml.Primitive, md toml.MetaData) (api.ExtendedConfig, error) { var toolsetConfigForTest ToolsetConfigForTest if err := md.PrimitiveDecode(primitive, &toolsetConfigForTest); err != nil { return nil, err } return &toolsetConfigForTest, nil } func (s *ToolsetConfigSuite) TestRegisterToolsetConfig() { s.Run("panics when registering duplicate toolset config parser", func() { s.Panics(func() { RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) }, "Expected panic when registering duplicate toolset config parser") }) } func (s *ToolsetConfigSuite) TestReadConfigValid() { RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) validConfigPath := s.writeConfig(` [toolset_configs.test-toolset] enabled = true endpoint = "https://example.com" timeout = 30 `) config, err := Read(validConfigPath, "") s.Run("returns no error for valid file with registered toolset config", func() { s.Require().NoError(err, "Expected no error for valid file, got %v", err) }) s.Run("returns config for valid file with registered toolset config", func() { s.Require().NotNil(config, "Expected non-nil config for valid file") }) s.Run("parses toolset config correctly", func() { toolsetConfig, ok := config.GetToolsetConfig("test-toolset") s.Require().True(ok, "Expected to find toolset config for 'test-toolset'") s.Require().NotNil(toolsetConfig, "Expected non-nil toolset config for 'test-toolset'") testToolsetConfig, ok := toolsetConfig.(*ToolsetConfigForTest) s.Require().True(ok, "Expected toolset config to be of type *ToolsetConfigForTest") s.Equal(true, testToolsetConfig.Enabled, "Expected Enabled to be true") s.Equal("https://example.com", testToolsetConfig.Endpoint, "Expected Endpoint to be 'https://example.com'") s.Equal(30, testToolsetConfig.Timeout, "Expected Timeout to be 30") }) } func (s *ToolsetConfigSuite) TestReadConfigInvalidToolsetConfig() { RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) invalidConfigPath := s.writeConfig(` [toolset_configs.test-toolset] enabled = true endpoint = "force-error" timeout = 30 `) config, err := Read(invalidConfigPath, "") s.Run("returns error for invalid toolset config", func() { s.Require().NotNil(err, "Expected error for invalid toolset config, got nil") s.ErrorContains(err, "validation error forced by test", "Expected validation error from toolset config") }) s.Run("returns nil config for invalid toolset config", func() { s.Nil(config, "Expected nil config for invalid toolset config") }) } func (s *ToolsetConfigSuite) TestReadConfigUnregisteredToolsetConfig() { unregisteredConfigPath := s.writeConfig(` [toolset_configs.unregistered-toolset] enabled = true endpoint = "https://example.com" timeout = 30 `) config, err := Read(unregisteredConfigPath, "") s.Run("returns no error for unregistered toolset config", func() { s.Require().NoError(err, "Expected no error for unregistered toolset config, got %v", err) }) s.Run("returns config for unregistered toolset config", func() { s.Require().NotNil(config, "Expected non-nil config for unregistered toolset config") }) s.Run("does not parse unregistered toolset config", func() { _, ok := config.GetToolsetConfig("unregistered-toolset") s.Require().False(ok, "Expected no toolset config for unregistered toolset") }) } func (s *ToolsetConfigSuite) TestConfigDirPathInContext() { var capturedDirPath string RegisterToolsetConfig("test-toolset", func(ctx context.Context, primitive toml.Primitive, md toml.MetaData) (api.ExtendedConfig, error) { capturedDirPath = ConfigDirPathFromContext(ctx) var toolsetConfigForTest ToolsetConfigForTest if err := md.PrimitiveDecode(primitive, &toolsetConfigForTest); err != nil { return nil, err } return &toolsetConfigForTest, nil }) configPath := s.writeConfig(` [toolset_configs.test-toolset] enabled = true endpoint = "https://example.com" timeout = 30 `) absConfigPath, err := filepath.Abs(configPath) s.Require().NoError(err, "test error: getting the absConfigPath should not fail") _, err = Read(configPath, "") s.Run("provides config directory path in context to parser", func() { s.Require().NoError(err, "Expected no error reading config") s.NotEmpty(capturedDirPath, "Expected non-empty directory path in context") s.Equal(filepath.Dir(absConfigPath), capturedDirPath, "Expected directory path to match config file directory") }) } func (s *ToolsetConfigSuite) TestExtendedConfigMergingAcrossDropIns() { // Test that extended configs (toolset_configs) are properly merged // when scattered across multiple drop-in files RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) tempDir := s.T().TempDir() // Create main config with initial toolset config mainConfigPath := filepath.Join(tempDir, "config.toml") err := os.WriteFile(mainConfigPath, []byte(` [toolset_configs.test-toolset] enabled = false endpoint = "from-main" timeout = 1 `), 0644) s.Require().NoError(err) // Create drop-in directory dropInDir := filepath.Join(tempDir, "conf.d") s.Require().NoError(os.Mkdir(dropInDir, 0755)) // First drop-in overrides some fields err = os.WriteFile(filepath.Join(dropInDir, "10-override.toml"), []byte(` [toolset_configs.test-toolset] enabled = true timeout = 10 `), 0644) s.Require().NoError(err) // Second drop-in overrides other fields err = os.WriteFile(filepath.Join(dropInDir, "20-final.toml"), []byte(` [toolset_configs.test-toolset] endpoint = "from-drop-in" timeout = 42 `), 0644) s.Require().NoError(err) config, err := Read(mainConfigPath, "") s.Require().NoError(err) s.Require().NotNil(config) toolsetConfig, ok := config.GetToolsetConfig("test-toolset") s.Require().True(ok, "Expected to find toolset config") testConfig, ok := toolsetConfig.(*ToolsetConfigForTest) s.Require().True(ok, "Expected toolset config to be *ToolsetConfigForTest") s.Run("merges enabled from first drop-in", func() { s.True(testConfig.Enabled, "enabled should be true from 10-override.toml") }) s.Run("merges endpoint from second drop-in", func() { s.Equal("from-drop-in", testConfig.Endpoint, "endpoint should be from 20-final.toml") }) s.Run("last drop-in wins for timeout", func() { s.Equal(42, testConfig.Timeout, "timeout should be 42 from 20-final.toml") }) } func (s *ToolsetConfigSuite) TestExtendedConfigFromDropInOnly() { // Test that extended configs work when defined only in drop-in files (not in main config) RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) tempDir := s.T().TempDir() // Create main config WITHOUT toolset config mainConfigPath := filepath.Join(tempDir, "config.toml") err := os.WriteFile(mainConfigPath, []byte(` log_level = 1 `), 0644) s.Require().NoError(err) // Create drop-in directory dropInDir := filepath.Join(tempDir, "conf.d") s.Require().NoError(os.Mkdir(dropInDir, 0755)) // Drop-in defines the toolset config err = os.WriteFile(filepath.Join(dropInDir, "10-toolset.toml"), []byte(` [toolset_configs.test-toolset] enabled = true endpoint = "from-drop-in-only" timeout = 99 `), 0644) s.Require().NoError(err) config, err := Read(mainConfigPath, "") s.Require().NoError(err) s.Require().NotNil(config) toolsetConfig, ok := config.GetToolsetConfig("test-toolset") s.Require().True(ok, "Expected to find toolset config from drop-in") testConfig, ok := toolsetConfig.(*ToolsetConfigForTest) s.Require().True(ok) s.Run("loads extended config from drop-in only", func() { s.True(testConfig.Enabled) s.Equal("from-drop-in-only", testConfig.Endpoint) s.Equal(99, testConfig.Timeout) }) } func (s *ToolsetConfigSuite) TestStandaloneConfigDirWithExtendedConfig() { // Test that extended configs work with standalone --config-dir (no main config) RegisterToolsetConfig("test-toolset", toolsetConfigForTestParser) tempDir := s.T().TempDir() // Create drop-in files only (no main config) err := os.WriteFile(filepath.Join(tempDir, "10-base.toml"), []byte(` [toolset_configs.test-toolset] enabled = false endpoint = "base" timeout = 1 `), 0644) s.Require().NoError(err) err = os.WriteFile(filepath.Join(tempDir, "20-override.toml"), []byte(` [toolset_configs.test-toolset] enabled = true timeout = 100 `), 0644) s.Require().NoError(err) // Read with standalone config-dir (empty config path) config, err := Read("", tempDir) s.Require().NoError(err) s.Require().NotNil(config) toolsetConfig, ok := config.GetToolsetConfig("test-toolset") s.Require().True(ok, "Expected to find toolset config in standalone mode") testConfig, ok := toolsetConfig.(*ToolsetConfigForTest) s.Require().True(ok) s.Run("merges extended config in standalone mode", func() { s.True(testConfig.Enabled, "enabled should be true from 20-override.toml") s.Equal("base", testConfig.Endpoint, "endpoint should be 'base' from 10-base.toml") s.Equal(100, testConfig.Timeout, "timeout should be 100 from 20-override.toml") }) } func (s *ToolsetConfigSuite) TestConfigDirPathInContextStandalone() { // Test that configDirPath is correctly set in context for standalone --config-dir var capturedDirPath string RegisterToolsetConfig("test-toolset", func(ctx context.Context, primitive toml.Primitive, md toml.MetaData) (api.ExtendedConfig, error) { capturedDirPath = ConfigDirPathFromContext(ctx) var toolsetConfigForTest ToolsetConfigForTest if err := md.PrimitiveDecode(primitive, &toolsetConfigForTest); err != nil { return nil, err } return &toolsetConfigForTest, nil }) tempDir := s.T().TempDir() err := os.WriteFile(filepath.Join(tempDir, "10-config.toml"), []byte(` [toolset_configs.test-toolset] enabled = true endpoint = "test" timeout = 1 `), 0644) s.Require().NoError(err) absTempDir, err := filepath.Abs(tempDir) s.Require().NoError(err) _, err = Read("", tempDir) s.Run("provides config directory path in context for standalone mode", func() { s.Require().NoError(err) s.NotEmpty(capturedDirPath, "Expected non-empty directory path in context") s.Equal(absTempDir, capturedDirPath, "Expected directory path to match config-dir") }) } func TestToolsetConfig(t *testing.T) { suite.Run(t, new(ToolsetConfigSuite)) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/containers/kubernetes-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server