-
Notifications
You must be signed in to change notification settings - Fork 32
fix(schema): make validateConfig validate actual Model structure #191
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -589,3 +589,42 @@ func TestConfig(t *testing.T) { | |
| } | ||
| } | ||
| } | ||
|
|
||
| func TestValidateConfigParsesModelNotModelConfig(t *testing.T) { | ||
| // This test verifies that validateConfig correctly parses the full Model structure, | ||
| // not just ModelConfig. Previously, validateConfig unmarshaled into ModelConfig, | ||
| // which always succeeded because all fields are optional. | ||
|
|
||
| // Test 1: Incomplete model with only config (should fail) | ||
| invalidJSON := `{ | ||
| "config": {"paramSize": "8b"} | ||
| }` | ||
|
|
||
| err := schema.ValidatorMediaTypeModelConfig.Validate(strings.NewReader(invalidJSON)) | ||
| if err == nil { | ||
| t.Fatalf("expected validation to fail for incomplete model") | ||
| } | ||
|
|
||
| // Test 2: Config-only JSON (should fail) | ||
| configOnlyJSON := `{ | ||
| "paramSize": "8b", | ||
| "architecture": "transformer" | ||
| }` | ||
|
|
||
| err = schema.ValidatorMediaTypeModelConfig.Validate(strings.NewReader(configOnlyJSON)) | ||
| if err == nil { | ||
| t.Fatalf("expected failure for config-only JSON without descriptor/modelfs, but got nil") | ||
| } | ||
|
|
||
| // Test 3: Valid full Model (should pass) | ||
| validJSON := `{ | ||
| "descriptor": {"name": "test-model"}, | ||
| "config": {"paramSize": "8b"}, | ||
| "modelfs": {"type": "layers", "diffIds": ["sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"]} | ||
| }` | ||
|
|
||
| err = schema.ValidatorMediaTypeModelConfig.Validate(strings.NewReader(validJSON)) | ||
| if err != nil { | ||
| t.Fatalf("expected valid Model to pass, but got error: %v", err) | ||
| } | ||
| } | ||
|
Comment on lines
+593
to
+630
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better test organization and clearer output on failures, it's a good practice to structure multiple test cases within a single test function using func TestValidateConfigParsesModelNotModelConfig(t *testing.T) {
// This test verifies that validateConfig correctly parses the full Model structure,
// not just ModelConfig. Previously, validateConfig unmarshaled into ModelConfig,
// which always succeeded because all fields are optional.
t.Run("Incomplete model with only config (should fail)", func(t *testing.T) {
invalidJSON := `{
"config": {"paramSize": "8b"}
}`
err := schema.ValidatorMediaTypeModelConfig.Validate(strings.NewReader(invalidJSON))
if err == nil {
t.Fatalf("expected validation to fail for incomplete model")
}
})
t.Run("Config-only JSON (should fail)", func(t *testing.T) {
configOnlyJSON := `{
"paramSize": "8b",
"architecture": "transformer"
}`
err := schema.ValidatorMediaTypeModelConfig.Validate(strings.NewReader(configOnlyJSON))
if err == nil {
t.Fatalf("expected failure for config-only JSON without descriptor/modelfs, but got nil")
}
})
t.Run("Valid full Model (should pass)", func(t *testing.T) {
validJSON := `{
"descriptor": {"name": "test-model"},
"config": {"paramSize": "8b"},
"modelfs": {"type": "layers", "diffIds": ["sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"]}
}`
err := schema.ValidatorMediaTypeModelConfig.Validate(strings.NewReader(validJSON))
if err != nil {
t.Fatalf("expected valid Model to pass, but got error: %v", err)
}
})
} |
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -114,11 +114,19 @@ var validateByMediaType = map[Validator]validateFunc{ | |||||||
| } | ||||||||
|
|
||||||||
| func validateConfig(buf []byte) error { | ||||||||
| mc := v1.ModelConfig{} | ||||||||
| var model v1.Model | ||||||||
|
|
||||||||
| err := json.Unmarshal(buf, &mc) | ||||||||
| err := json.Unmarshal(buf, &model) | ||||||||
| if err != nil { | ||||||||
| return fmt.Errorf("config format mismatch: %w", err) | ||||||||
| return fmt.Errorf("invalid model structure: %w", err) | ||||||||
| } | ||||||||
|
Comment on lines
116
to
+122
|
||||||||
|
|
||||||||
| // Minimal structural validation for required fields | ||||||||
| if model.Descriptor.Name == "" { | ||||||||
| return fmt.Errorf("missing descriptor.name") | ||||||||
| } | ||||||||
|
Comment on lines
+125
to
+127
|
||||||||
| if model.Descriptor.Name == "" { | |
| return fmt.Errorf("missing descriptor.name") | |
| } |
Copilot
AI
Mar 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because v1.Model.Descriptor and v1.Model.ModelFS are non-pointer structs, json.Unmarshal can’t distinguish between a missing descriptor/modelfs object and an empty one. That leads to potentially misleading errors (e.g., a document missing descriptor entirely will be reported as “missing descriptor.name”). Consider unmarshalling into a lightweight struct with *json.RawMessage/pointer fields so you can accurately detect missing top-level fields and return a clearer error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test assumes
descriptor.nameis required for a valid document, but the current schema/docs treat it as optional. Unless you’re also updating the schema/docs to requirename, adjust the tests to validate only the required top-level Model shape (e.g., presence ofdescriptor,config, andmodelfswith non-emptydiffIds).