Add more validation for free-form server fields (#272)
<!-- Provide a brief summary of your changes --> The changes are intended to create validators for all the free-form fields. Please find the details of the validation of different field below. - Repository.Source: only github and gitlab is accepted. - Repository.Url - It should be a valid github or gitlab URL. Created regex for both. - Server.Name - Max 200 char can be there. Reverse domain name verification is part of another PR (not owned by me). - Package.Name - Max 200 char and no spaces. - Server.Description - Max 100 char. - Remote.Url - It should be valid URL. ## Motivation and Context <!-- Why is this change needed? What problem does it solve? --> The motivation was to make the code clean and add base code for more validator for different objects like Repository etc. https://github.com/modelcontextprotocol/registry/issues/97 ## How Has This Been Tested? It's tested via UTs. Added UT's for all the validations. ## Breaking Changes Yes ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [ ] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [x] I have added appropriate error handling - [ ] I have added or updated documentation as needed Co-authored-by: Avish Porwal <avishporwal@microsoft.com> Co-authored-by: Adam Jones <adamj+git@anthropic.com>
This commit is contained in:
parent
5fb6ee2982
commit
c3b72ef3a6
1 changed files with 484 additions and 12 deletions
248
internal/validators/validators_test.go
Normal file
248
internal/validators/validators_test.go
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
package validators_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/modelcontextprotocol/registry/internal/model"
|
||||
"github.com/modelcontextprotocol/registry/internal/validators"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestObjectValidator_Validate(t *testing.T) {
|
||||
validator := validators.NewObjectValidator()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
serverDetail model.ServerDetail
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "valid server detail with all fields",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
ID: "owner/repo",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Packages: []model.Package{
|
||||
{
|
||||
Name: "test-package",
|
||||
RegistryName: "npm",
|
||||
},
|
||||
},
|
||||
Remotes: []model.Remote{
|
||||
{
|
||||
URL: "https://example.com/remote",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "server with invalid repository source",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://bitbucket.org/owner/repo",
|
||||
Source: "bitbucket", // Not in validSources
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrInvalidRepositoryURL.Error(),
|
||||
},
|
||||
{
|
||||
name: "server with invalid GitHub URL format",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner", // Missing repo name
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrInvalidRepositoryURL.Error(),
|
||||
},
|
||||
{
|
||||
name: "server with invalid GitLab URL format",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://gitlab.com", // Missing owner and repo
|
||||
Source: "gitlab",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrInvalidRepositoryURL.Error(),
|
||||
},
|
||||
{
|
||||
name: "package with spaces in name",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Packages: []model.Package{
|
||||
{
|
||||
Name: "test package with spaces",
|
||||
RegistryName: "npm",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrPackageNameHasSpaces.Error(),
|
||||
},
|
||||
{
|
||||
name: "multiple packages with one invalid",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Packages: []model.Package{
|
||||
{
|
||||
Name: "valid-package",
|
||||
RegistryName: "npm",
|
||||
},
|
||||
{
|
||||
Name: "invalid package", // Has space
|
||||
RegistryName: "pip",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrPackageNameHasSpaces.Error(),
|
||||
},
|
||||
{
|
||||
name: "remote with invalid URL",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Remotes: []model.Remote{
|
||||
{
|
||||
URL: "not-a-valid-url",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrInvalidRemoteURL.Error(),
|
||||
},
|
||||
{
|
||||
name: "remote with missing scheme",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Remotes: []model.Remote{
|
||||
{
|
||||
URL: "example.com/remote",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrInvalidRemoteURL.Error(),
|
||||
},
|
||||
{
|
||||
name: "multiple remotes with one invalid",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Remotes: []model.Remote{
|
||||
{
|
||||
URL: "https://valid.com/remote",
|
||||
},
|
||||
{
|
||||
URL: "invalid-url",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: validators.ErrInvalidRemoteURL.Error(),
|
||||
},
|
||||
{
|
||||
name: "server detail with nil packages and remotes",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Packages: nil,
|
||||
Remotes: nil,
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "server detail with empty packages and remotes slices",
|
||||
serverDetail: model.ServerDetail{
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
VersionDetail: model.VersionDetail{
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Packages: []model.Package{},
|
||||
Remotes: []model.Remote{},
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validator.Validate(&tt.serverDetail)
|
||||
|
||||
if tt.expectedError == "" {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.expectedError)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue