@Test public void checkProtobufSchemaCompatibility() throws Exception { ObjectMapper objectMapper = new ObjectMapper(); ArrayNode nodes = (ArrayNode) objectMapper.readTree(readFile("diff-schema-examples.json")); for (int i = 0; i < nodes.size(); i++) { final ObjectNode testCase = (ObjectNode) nodes.get(i); String originalSchema = testCase.get("original_schema").asText(); String updateSchema = testCase.get("update_schema").asText(); ProtoFileElement original = ProtoParser.Companion.parse( Location.get("unknown"), originalSchema); ProtoFileElement update = ProtoParser.Companion.parse( Location.get("unknown"), updateSchema); List<SchemaReference> originalSchemaRefs = new ArrayList<>(); ArrayNode originalRefs = (ArrayNode) testCase.get("original_references"); if (originalRefs != null) { for (JsonNode ref : originalRefs) { ObjectNode node = (ObjectNode) ref; SchemaReference schemaRef = new SchemaReference( node.get("name").asText(), node.get("subject").asText(), node.get("version").asInt()); originalSchemaRefs.add(schemaRef); } } List<SchemaReference> updateSchemaRefs = new ArrayList<>(); ArrayNode updateRefs = (ArrayNode) testCase.get("update_references"); if (updateRefs != null) { for (JsonNode ref : updateRefs) { ObjectNode node = (ObjectNode) ref; SchemaReference schemaRef = new SchemaReference( node.get("name").asText(), node.get("subject").asText(), node.get("version").asInt()); updateSchemaRefs.add(schemaRef); } } Map<String, ProtoFileElement> originalDependencies = new HashMap<>(); ArrayNode originalDeps = (ArrayNode) testCase.get("original_dependencies"); if (originalDeps != null) { for (JsonNode dep : originalDeps) { ObjectNode node = (ObjectNode) dep; String schema = node.get("dependency").asText(); ProtoFileElement file = ProtoParser.Companion.parse( Location.get("unknown"), schema); originalDependencies.put(node.get("name").asText(), file); } } Map<String, ProtoFileElement> updateDependencies = new HashMap<>(); ArrayNode updateDeps = (ArrayNode) testCase.get("update_dependencies"); if (updateDeps != null) { for (JsonNode dep : updateDeps) { ObjectNode node = (ObjectNode) dep; String schema = node.get("dependency").asText(); ProtoFileElement file = ProtoParser.Companion.parse( Location.get("unknown"), schema); updateDependencies.put(node.get("name").asText(), file); } } final ArrayNode changes = (ArrayNode) testCase.get("changes"); boolean isCompatible = testCase.get("compatible").asBoolean(); final List<String> errorMessages = new ArrayList<>(); for (int j = 0; j < changes.size(); j++) { errorMessages.add(changes.get(j).asText()); } final String description = testCase.get("description").asText(); List<Difference> differences = SchemaDiff.compare( new ProtobufSchema(original, originalSchemaRefs, originalDependencies), new ProtobufSchema(update, updateSchemaRefs, updateDependencies) ); final List<Difference> incompatibleDiffs = differences.stream() .filter(diff -> !SchemaDiff.COMPATIBLE_CHANGES.contains(diff.getType())) .collect(Collectors.toList()); assertThat( description, differences.stream() .map(change -> change.getType().toString() + " " + change.getFullPath()) .collect(toList()), is(errorMessages) ); assertEquals(description, isCompatible, incompatibleDiffs.isEmpty()); } }
public static List<Difference> compare( final ProtobufSchema original, final ProtobufSchema update ) { Map<String, SchemaReference> originalReferences = original.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, SchemaReference> updateReferences = update.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, ProtoFileElement> originalDependencies = original.dependencies(); Map<String, ProtoFileElement> updateDependencies = update.dependencies(); final Context ctx = new Context(COMPATIBLE_CHANGES); collectContextInfoForRefs(ctx, originalReferences, originalDependencies, true); collectContextInfoForRefs(ctx, updateReferences, updateDependencies, false); compare(ctx, original.rawSchema(), update.rawSchema()); return ctx.getDifferences(); }
SchemaDiff { public static List<Difference> compare( final ProtobufSchema original, final ProtobufSchema update ) { Map<String, SchemaReference> originalReferences = original.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, SchemaReference> updateReferences = update.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, ProtoFileElement> originalDependencies = original.dependencies(); Map<String, ProtoFileElement> updateDependencies = update.dependencies(); final Context ctx = new Context(COMPATIBLE_CHANGES); collectContextInfoForRefs(ctx, originalReferences, originalDependencies, true); collectContextInfoForRefs(ctx, updateReferences, updateDependencies, false); compare(ctx, original.rawSchema(), update.rawSchema()); return ctx.getDifferences(); } }
SchemaDiff { public static List<Difference> compare( final ProtobufSchema original, final ProtobufSchema update ) { Map<String, SchemaReference> originalReferences = original.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, SchemaReference> updateReferences = update.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, ProtoFileElement> originalDependencies = original.dependencies(); Map<String, ProtoFileElement> updateDependencies = update.dependencies(); final Context ctx = new Context(COMPATIBLE_CHANGES); collectContextInfoForRefs(ctx, originalReferences, originalDependencies, true); collectContextInfoForRefs(ctx, updateReferences, updateDependencies, false); compare(ctx, original.rawSchema(), update.rawSchema()); return ctx.getDifferences(); }  }
SchemaDiff { public static List<Difference> compare( final ProtobufSchema original, final ProtobufSchema update ) { Map<String, SchemaReference> originalReferences = original.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, SchemaReference> updateReferences = update.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, ProtoFileElement> originalDependencies = original.dependencies(); Map<String, ProtoFileElement> updateDependencies = update.dependencies(); final Context ctx = new Context(COMPATIBLE_CHANGES); collectContextInfoForRefs(ctx, originalReferences, originalDependencies, true); collectContextInfoForRefs(ctx, updateReferences, updateDependencies, false); compare(ctx, original.rawSchema(), update.rawSchema()); return ctx.getDifferences(); }  static List<Difference> compare(
      final ProtobufSchema original,
      final ProtobufSchema update
  ); static Optional<FieldElement> findField(String name, List<FieldElement> options); static void compareTypeElements(
      final Context ctx, final List<TypeElement> original, final List<TypeElement> update
  ); }
SchemaDiff { public static List<Difference> compare( final ProtobufSchema original, final ProtobufSchema update ) { Map<String, SchemaReference> originalReferences = original.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, SchemaReference> updateReferences = update.references().stream() .collect(Collectors.toMap(SchemaReference::getName, r -> r)); Map<String, ProtoFileElement> originalDependencies = original.dependencies(); Map<String, ProtoFileElement> updateDependencies = update.dependencies(); final Context ctx = new Context(COMPATIBLE_CHANGES); collectContextInfoForRefs(ctx, originalReferences, originalDependencies, true); collectContextInfoForRefs(ctx, updateReferences, updateDependencies, false); compare(ctx, original.rawSchema(), update.rawSchema()); return ctx.getDifferences(); }  static List<Difference> compare(
      final ProtobufSchema original,
      final ProtobufSchema update
  ); static Optional<FieldElement> findField(String name, List<FieldElement> options); static void compareTypeElements(
      final Context ctx, final List<TypeElement> original, final List<TypeElement> update
  ); static final Set<Difference.Type> COMPATIBLE_CHANGES; }