Skip to content

Commit 331c202

Browse files
zeevdrclaude
andauthored
test(e2e): cover validation-limit rejections (#328)
* test(e2e): cover validation-limit rejections (#283) PR #254 added configurable schema ingest limits (MaxFields, MaxDocBytes) and PR #256 added JSON-Schema compile-time bounds. The validators have unit tests; this lands the live e2e coverage of the user-facing rejection paths. Lower the docker-compose service's caps to small values (SCHEMA_MAX_FIELDS=100, SCHEMA_MAX_DOC_BYTES=4096) so the new tests can trip them with cheap payloads. Existing fixtures use at most a few fields and well under 1 KiB of YAML, so other e2e tests are unaffected. Add three tests in e2e/validation_limits_test.go: - TestValidationLimits_MaxFieldsRejected — CreateSchema with 101 fields returns InvalidArgument and the message cites the configured cap. - TestValidationLimits_MaxFieldsAtLimitAccepted — exactly 100 fields is accepted; the cap is inclusive at the limit. - TestValidationLimits_MaxDocBytesRejected — ImportSchema with a YAML body padded past the cap is rejected before the parser runs. The JSON-Schema MaxDepth path is intentionally not covered here: internal/validation/validator.go silently swallows newJSONSchemaValidator errors at line 147 (constraints.JsonSchema branch), so a depth-exceeded schema is accepted at CreateSchema and only surfaces later as a missing JSON-Schema check. That swallow is worth a separate issue; the depth trigger itself is unit-tested in internal/validation. Closes #283 Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 70053ba commit 331c202

2 files changed

Lines changed: 103 additions & 0 deletions

File tree

docker-compose.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ services:
7272
HTTP_PORT: "8080"
7373
USAGE_FLUSH_INTERVAL: "1s"
7474
INSECURE_LISTEN: "1"
75+
# Tight ingest limits so the validation-limit e2e tests can trip
76+
# them with small payloads. Existing fixtures use at most a few
77+
# fields and small YAMLs (< 1 KiB), well under these caps.
78+
SCHEMA_MAX_FIELDS: "100"
79+
SCHEMA_MAX_DOC_BYTES: "4096"
7580
ports:
7681
- "9090:9090"
7782
- "8080:8080"

e2e/validation_limits_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//go:build e2e
2+
3+
package e2e
4+
5+
import (
6+
"context"
7+
"errors"
8+
"fmt"
9+
"strings"
10+
"testing"
11+
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
15+
"github.com/opendecree/decree/sdk/adminclient"
16+
)
17+
18+
// docker-compose pins the server to:
19+
//
20+
// SCHEMA_MAX_FIELDS=100
21+
// SCHEMA_MAX_DOC_BYTES=4096
22+
//
23+
// so these tests can trip each limit with small payloads.
24+
const (
25+
maxFields = 100
26+
maxDocBytes = 4096
27+
)
28+
29+
// TestValidationLimits_MaxFieldsRejected: CreateSchema with more fields
30+
// than the configured cap is rejected with InvalidArgument and a message
31+
// citing the limit.
32+
func TestValidationLimits_MaxFieldsRejected(t *testing.T) {
33+
conn := dial(t)
34+
admin := newAdminClient(conn)
35+
ctx := context.Background()
36+
37+
fields := make([]adminclient.Field, maxFields+1)
38+
for i := range fields {
39+
fields[i] = adminclient.Field{
40+
Path: fmt.Sprintf("f.field_%d", i),
41+
Type: "FIELD_TYPE_STRING",
42+
}
43+
}
44+
45+
_, err := admin.CreateSchema(ctx, fmt.Sprintf("limits-fields-%s", randSuffix()), fields, "")
46+
require.Error(t, err)
47+
assert.True(t, errors.Is(err, adminclient.ErrInvalidArgument))
48+
assert.Contains(t, err.Error(), fmt.Sprintf("exceeds limit of %d", maxFields))
49+
}
50+
51+
// TestValidationLimits_MaxFieldsAtLimitAccepted: CreateSchema with
52+
// exactly maxFields entries succeeds — the cap is inclusive at the limit
53+
// and exclusive only above it.
54+
func TestValidationLimits_MaxFieldsAtLimitAccepted(t *testing.T) {
55+
conn := dial(t)
56+
admin := newAdminClient(conn)
57+
ctx := context.Background()
58+
59+
fields := make([]adminclient.Field, maxFields)
60+
for i := range fields {
61+
fields[i] = adminclient.Field{
62+
Path: fmt.Sprintf("f.field_%d", i),
63+
Type: "FIELD_TYPE_STRING",
64+
}
65+
}
66+
67+
schemaName := fmt.Sprintf("limits-fields-ok-%s", randSuffix())
68+
s, err := admin.CreateSchema(ctx, schemaName, fields, "")
69+
require.NoError(t, err)
70+
t.Cleanup(func() { _ = admin.DeleteSchema(ctx, s.ID) })
71+
}
72+
73+
// TestValidationLimits_MaxDocBytesRejected: ImportSchema with a YAML body
74+
// larger than SCHEMA_MAX_DOC_BYTES is rejected with InvalidArgument and a
75+
// message citing the limit.
76+
func TestValidationLimits_MaxDocBytesRejected(t *testing.T) {
77+
conn := dial(t)
78+
admin := newAdminClient(conn)
79+
ctx := context.Background()
80+
81+
// Build a syntactically valid YAML, then pad with a large comment so
82+
// the byte count exceeds the cap. The pre-parse byte check fires
83+
// before the YAML parser cares about comment size.
84+
header := fmt.Sprintf(`spec_version: "v1"
85+
name: limits-bytes-%s
86+
fields:
87+
app.name:
88+
type: string
89+
`, randSuffix())
90+
padding := "\n# " + strings.Repeat("x", maxDocBytes)
91+
yaml := []byte(header + padding)
92+
require.Greater(t, len(yaml), maxDocBytes, "test fixture must exceed the cap")
93+
94+
_, err := admin.ImportSchema(ctx, yaml)
95+
require.Error(t, err)
96+
assert.True(t, errors.Is(err, adminclient.ErrInvalidArgument))
97+
assert.Contains(t, err.Error(), fmt.Sprintf("exceeds limit of %d", maxDocBytes))
98+
}

0 commit comments

Comments
 (0)