Skip to content

Commit b615268

Browse files
committed
fix(avro): include default values in schema fingerprint for correct dedup
Schemas differing only in field defaults (e.g., with vs without "default":"a") were producing identical fingerprints, causing the dedup check to short-circuit compatibility validation. This meant registering a schema with a removed default would silently succeed under BACKWARD_TRANSITIVE/FULL_TRANSITIVE instead of returning 409. Verified against Confluent v8.1.1. Also fixes Avro transitive BDD tests: - Remove @pending-impl from BACKWARD_TRANSITIVE and FULL_TRANSITIVE tests - Fix FORWARD_TRANSITIVE expectation: adding field without default is compatible (old readers ignore unknown fields) 1285 BDD scenarios passing, 0 failures.
1 parent 34749eb commit b615268

File tree

2 files changed

+9
-6
lines changed

2 files changed

+9
-6
lines changed

internal/schema/avro/parser.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,19 @@ func canonicalizeObject(obj map[string]interface{}) string {
230230
func canonicalizeField(field map[string]interface{}) string {
231231
parts := make([]string, 0)
232232

233-
// Field order: name, type
233+
// Field order: name, type, default
234+
// Note: default is included for fingerprinting so that schemas differing
235+
// only in default values are treated as distinct (important for compatibility).
234236
if name, ok := field["name"]; ok {
235237
parts = append(parts, fmt.Sprintf(`"name":"%v"`, name))
236238
}
237239
if typ, ok := field["type"]; ok {
238240
parts = append(parts, fmt.Sprintf(`"type":%s`, canonicalizeValue(typ)))
239241
}
242+
if def, ok := field["default"]; ok {
243+
defBytes, _ := json.Marshal(def)
244+
parts = append(parts, fmt.Sprintf(`"default":%s`, string(defBytes)))
245+
}
240246

241247
return "{" + strings.Join(parts, ",") + "}"
242248
}

tests/bdd/features/avro_compatibility_exhaustive.feature

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,6 @@ Feature: Avro Compatibility — Exhaustive (Confluent v8.1.1 Compatibility)
440440
"""
441441
Then the response status should be 200
442442

443-
@pending-impl
444443
Scenario: BACKWARD_TRANSITIVE — removing default transitively is incompatible
445444
Given the global compatibility level is "NONE"
446445
And subject "avro-ex-bt-nodef" has schema:
@@ -475,8 +474,7 @@ Feature: Avro Compatibility — Exhaustive (Confluent v8.1.1 Compatibility)
475474
"""
476475
Then the response status should be 200
477476

478-
@pending-impl
479-
Scenario: FORWARD_TRANSITIVE — adding field without default transitively is incompatible
477+
Scenario: FORWARD_TRANSITIVE — adding field without default is compatible (old readers ignore new fields)
480478
Given the global compatibility level is "NONE"
481479
And subject "avro-ex-ft-add-nodef" has schema:
482480
"""
@@ -491,7 +489,7 @@ Feature: Avro Compatibility — Exhaustive (Confluent v8.1.1 Compatibility)
491489
"""
492490
{"type":"record","name":"R","fields":[{"name":"f1","type":"string"},{"name":"f3","type":"string"}]}
493491
"""
494-
Then the response status should be 409
492+
Then the response status should be 200
495493

496494
Scenario: FULL_TRANSITIVE — safe evolution with defaults is compatible
497495
Given the global compatibility level is "NONE"
@@ -510,7 +508,6 @@ Feature: Avro Compatibility — Exhaustive (Confluent v8.1.1 Compatibility)
510508
"""
511509
Then the response status should be 200
512510

513-
@pending-impl
514511
Scenario: FULL_TRANSITIVE — field without default transitively is incompatible
515512
Given the global compatibility level is "NONE"
516513
And subject "avro-ex-fullt-nodef" has schema:

0 commit comments

Comments
 (0)