Skip to content

Update unit test coverage for tools + secret packages #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ make format
make lint
```

## Testing

### Running Tests

```bash
# Run all unit tests
make test

# Run integration tests
make integration
```

### Unit Test Coverage

```bash
# Generate HTML coverage report for ALL packages in one view
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

go test -cover -coverprofile=coverage.out ./... -short
go tool cover -html=coverage.out -o coverage.html && open coverage.html
```

## Open a Pull Request

1. Fork the repository
Expand Down
63 changes: 63 additions & 0 deletions cmd/docker-mcp/secret-management/secret/secret_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package secret

import (
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetSecretKey(t *testing.T) {
result := getSecretKey("mykey")
assert.Equal(t, "sm_mykey", result)
}

func TestParseArg(t *testing.T) {
// Test key=value parsing
secret, err := ParseArg("key=value", SetOpts{Provider: Credstore})
require.NoError(t, err)
assert.Equal(t, "key", secret.key)
assert.Equal(t, "value", secret.val)

// Test key-only for non-direct providers
secret, err = ParseArg("keyname", SetOpts{Provider: "oauth/github"})
require.NoError(t, err)
assert.Equal(t, "keyname", secret.key)
assert.Empty(t, secret.val)

// Test error on key=value with non-direct provider
_, err = ParseArg("key=value", SetOpts{Provider: "oauth/github"})
assert.Error(t, err)
}

func TestIsDirectValueProvider(t *testing.T) {
assert.True(t, isDirectValueProvider(""))
assert.True(t, isDirectValueProvider(Credstore))
assert.False(t, isDirectValueProvider("oauth/github"))
}

func TestIsValidProvider(t *testing.T) {
// Valid providers
assert.True(t, IsValidProvider(""))
assert.True(t, IsValidProvider(Credstore))
assert.True(t, IsValidProvider("oauth/github"))
assert.True(t, IsValidProvider("oauth/google"))

// Invalid providers
assert.False(t, IsValidProvider("invalid"))
assert.False(t, IsValidProvider("oauth"))
}

func TestIsErrDecryption(t *testing.T) {
// Test decryption error detection
decryptErr := errors.New("gpg: decryption failed: No secret key")
assert.True(t, isErrDecryption(decryptErr))

// Test other errors
otherErr := errors.New("some other error")
assert.False(t, isErrDecryption(otherErr))

// Test nil
assert.False(t, isErrDecryption(nil))
}
55 changes: 55 additions & 0 deletions cmd/docker-mcp/tools/tools_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/docker/docker/api/types/volume"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -318,3 +319,57 @@ func withSampleCatalog() option {
writeFile(t, filepath.Join(home, ".docker/mcp/catalogs/docker-mcp.yaml"), []byte(catalogContent))
}
}

// Unit tests for call

func TestCallNoToolName(t *testing.T) {
err := Call(context.Background(), "2", []string{}, false, []string{})
require.Error(t, err)
assert.Equal(t, "no tool name provided", err.Error())
}

func TestToText(t *testing.T) {
// Test basic functionality - joining multiple text contents
response := &mcp.CallToolResult{
Content: []mcp.Content{
&mcp.TextContent{Text: "First"},
&mcp.TextContent{Text: "Second"},
},
}
result := toText(response)
assert.Equal(t, "First\nSecond", result)
}

func TestParseArgs(t *testing.T) {
// Test key=value parsing
result := parseArgs([]string{"key1=value1", "key2=value2"})
expected := map[string]any{"key1": "value1", "key2": "value2"}
assert.Equal(t, expected, result)

// Test duplicate keys become arrays
result = parseArgs([]string{"tag=red", "tag=blue"})
expected = map[string]any{"tag": []any{"red", "blue"}}
assert.Equal(t, expected, result)
}

// Unit tests for list

func TestToolDescription(t *testing.T) {
// Test that title annotation takes precedence over description
tool := &mcp.Tool{
Description: "Longer description",
Annotations: &mcp.ToolAnnotations{Title: "Short Title"},
}
result := toolDescription(tool)
assert.Equal(t, "Short Title", result)
}

func TestDescriptionSummary(t *testing.T) {
// Test key behavior: stops at first sentence
result := descriptionSummary("First sentence. Second sentence.")
assert.Equal(t, "First sentence.", result)

// Test key behavior: stops at "Error Responses:"
result = descriptionSummary("Tool description.\nError Responses:\n- 404 if not found")
assert.Equal(t, "Tool description.", result)
}