diff --git a/elasticgraph-datastore_core/spec/integration/elastic_graph/datastore_core/index_definition/rollover_index_template_spec.rb b/elasticgraph-datastore_core/spec/integration/elastic_graph/datastore_core/index_definition/rollover_index_template_spec.rb index 806440f80..03d04113c 100644 --- a/elasticgraph-datastore_core/spec/integration/elastic_graph/datastore_core/index_definition/rollover_index_template_spec.rb +++ b/elasticgraph-datastore_core/spec/integration/elastic_graph/datastore_core/index_definition/rollover_index_template_spec.rb @@ -8,6 +8,7 @@ require "elastic_graph/constants" require "elastic_graph/datastore_core/index_definition" +require "elastic_graph/json_ingestion/schema_definition/api_extension" require "elastic_graph/support/hash_util" require "stringio" require_relative "implementation_shared_examples" @@ -16,6 +17,12 @@ module ElasticGraph class DatastoreCore module IndexDefinition RSpec.describe RolloverIndexTemplate, :uses_datastore, :builds_indexer do + # Documents indexed by these specs are validated against the JSON schemas, so the schemas + # defined in this file all include the JSON ingestion schema definition extension. + def build_datastore_core(**options, &block) + super(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], **options, &block) + end + # Use different index names than any other tests use, because most tests expect a specific index # configuration (based on `config/schema.graphql`) and we do not want to mess with it here. let(:index_prefix) { unique_index_name } diff --git a/elasticgraph-graphql/spec/acceptance/elasticgraph_graphql_acceptance_support.rb b/elasticgraph-graphql/spec/acceptance/elasticgraph_graphql_acceptance_support.rb index c384a1dd0..3450b3bd4 100644 --- a/elasticgraph-graphql/spec/acceptance/elasticgraph_graphql_acceptance_support.rb +++ b/elasticgraph-graphql/spec/acceptance/elasticgraph_graphql_acceptance_support.rb @@ -7,6 +7,7 @@ # frozen_string_literal: true require "elastic_graph/graphql/datastore_search_router" +require "elastic_graph/json_ingestion/schema_definition/api_extension" require "elastic_graph/schema_definition/schema_elements/type_namer" require "elastic_graph/spec_support/builds_admin" require "graphql" @@ -92,6 +93,9 @@ def self.with_both_casing_forms(&block) derived_type_name_formats: derived_type_name_formats, type_name_overrides: {Cursor: "String"}, enum_value_overrides_by_type: enum_value_overrides_by_type, + # The camelCase schema definition below is derived from the repository's main test schema, + # which uses the JSON ingestion schema definition DSL, so it requires this extension. + schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: ->(schema) do # standard:disable Security/Eval -- it's ok here in a test. schema.as_active_instance { eval(camel_case_schema_def) } diff --git a/elasticgraph-graphql/spec/integration/elastic_graph/graphql/datastore_query/misc_spec.rb b/elasticgraph-graphql/spec/integration/elastic_graph/graphql/datastore_query/misc_spec.rb index cba1b2f07..9a22a9f3f 100644 --- a/elasticgraph-graphql/spec/integration/elastic_graph/graphql/datastore_query/misc_spec.rb +++ b/elasticgraph-graphql/spec/integration/elastic_graph/graphql/datastore_query/misc_spec.rb @@ -9,6 +9,7 @@ require_relative "datastore_query_integration_support" require "elastic_graph/errors" require "elastic_graph/graphql/datastore_search_router" +require "elastic_graph/json_ingestion/schema_definition/api_extension" module ElasticGraph class GraphQL @@ -85,7 +86,7 @@ def msearch(body:, **args, &block) context "when the indexed type has nested `default_sort_fields`" do let(:graphql) do - build_graphql(schema_definition: lambda do |schema| + build_graphql(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: lambda do |schema| schema.object_type "Money" do |t| t.field "currency", "String!" t.field "amount_cents", "Int!" diff --git a/elasticgraph-graphql/spec/integration/elastic_graph/graphql/resolvers/nested_relationships_spec.rb b/elasticgraph-graphql/spec/integration/elastic_graph/graphql/resolvers/nested_relationships_spec.rb index a09583209..2657de370 100644 --- a/elasticgraph-graphql/spec/integration/elastic_graph/graphql/resolvers/nested_relationships_spec.rb +++ b/elasticgraph-graphql/spec/integration/elastic_graph/graphql/resolvers/nested_relationships_spec.rb @@ -7,6 +7,7 @@ # frozen_string_literal: true require "elastic_graph/graphql/resolvers/nested_relationships" +require "elastic_graph/json_ingestion/schema_definition/api_extension" module ElasticGraph class GraphQL @@ -16,7 +17,7 @@ module Resolvers # is implemented via a filter on `id` (the search routing field) context "when the field being resolved is a relay connection field", :expect_search_routing do let(:graphql) do - build_graphql(schema_definition: lambda do |schema| + build_graphql(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: lambda do |schema| schema.object_type "Component" do |t| t.field "id", "ID!" t.field "name", "String!" @@ -62,7 +63,7 @@ module Resolvers describe "a relates_to_many/relates_to_one bidirectional relationship with an array foreign key from the one to the many" do let(:graphql) do - build_graphql(schema_definition: lambda do |schema| + build_graphql(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: lambda do |schema| schema.object_type "Money" do |t| t.field "currency", "String!" t.field "amount_cents", "Int" @@ -241,7 +242,7 @@ module Resolvers describe "a relates_to_many/relates_to_one bidirectional relationship with a scalar foreign key from the many to the one" do let(:graphql) do - build_graphql(schema_definition: lambda do |schema| + build_graphql(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: lambda do |schema| schema.object_type "ElectricalPart" do |t| t.field "id", "ID!" t.field "name", "String!" @@ -381,7 +382,7 @@ module Resolvers describe "a relates_to_many/relates_to_many bidirectional relationship with an array foreign key from a many to a many" do let(:graphql) do - build_graphql(schema_definition: lambda do |schema| + build_graphql(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: lambda do |schema| schema.object_type "Component" do |t| t.field "id", "ID!" t.field "name", "String!" @@ -573,7 +574,7 @@ module Resolvers describe "a relates_to_one/relates_to_one bidirectional relationship with a scalar foreign key from a one to a one" do let(:graphql) do - build_graphql(schema_definition: lambda do |schema| + build_graphql(schema_definition_extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], schema_definition: lambda do |schema| schema.object_type "Manufacturer" do |t| t.field "id", "ID!" t.field "name", "String" diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_executor_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_executor_spec.rb index 59d3339f4..8403b2498 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_executor_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/query_executor_spec.rb @@ -447,7 +447,6 @@ def resolve(field:, object:, args:, context:) schema.scalar_type "Operands" do |t| t.mapping type: nil - t.json_schema type: "null" end schema.object_type "Widget" do |t| diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/resolvers/get_record_field_value_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/resolvers/get_record_field_value_spec.rb index 89479c1f8..10c32c891 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/resolvers/get_record_field_value_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/resolvers/get_record_field_value_spec.rb @@ -19,7 +19,6 @@ module Resolvers self.schema_artifacts = generate_schema_artifacts do |schema| schema.scalar_type "MyInt" do |t| t.mapping type: "integer" - t.json_schema type: "integer" end schema.object_type "PersonIdentifiers" do |t| diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/scalar_coercion_adapters/no_op_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/scalar_coercion_adapters/no_op_spec.rb index cb84c3ff4..73bb09df8 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/scalar_coercion_adapters/no_op_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/scalar_coercion_adapters/no_op_spec.rb @@ -14,7 +14,6 @@ module ScalarCoercionAdapters RSpec.describe "NoOp" do include_context("scalar coercion adapter support", "SomeCustomScalar", schema_definition: ->(schema) do schema.scalar_type "SomeCustomScalar" do |t| - t.json_schema type: "null" t.mapping type: nil end diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema/type_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema/type_spec.rb index 48dc10135..90f21fdb8 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema/type_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema/type_spec.rb @@ -955,7 +955,6 @@ def search_index_definitions_from(type_name: "TheType") schema = define_schema do |s| s.scalar_type "CustomScalar" do |t| t.mapping type: "keyword" - t.json_schema type: "string" end end @@ -967,7 +966,6 @@ def search_index_definitions_from(type_name: "TheType") schema = define_schema do |s| s.scalar_type "CustomScalar" do |t| t.mapping type: "keyword" - t.json_schema type: "string" t.grouping_missing_value_placeholder "MISSING" end end @@ -980,7 +978,6 @@ def search_index_definitions_from(type_name: "TheType") schema = define_schema do |s| s.scalar_type "CustomScalar" do |t| t.mapping type: "keyword" - t.json_schema type: "string" t.grouping_missing_value_placeholder nil end end @@ -1007,7 +1004,6 @@ def search_index_definitions_from(type_name: "TheType") t.field "name", "String" t.field "count", "Int" t.field "price", "Float" - t.field "big_number", "JsonSafeLong" t.index "things" end end @@ -1016,7 +1012,6 @@ def search_index_definitions_from(type_name: "TheType") expect(schema.type_named("String").grouping_missing_value_placeholder).to eq MISSING_STRING_PLACEHOLDER_VALUE expect(schema.type_named("Int").grouping_missing_value_placeholder).to eq MISSING_NUMERIC_PLACEHOLDER expect(schema.type_named("Float").grouping_missing_value_placeholder).to eq MISSING_NUMERIC_PLACEHOLDER - expect(schema.type_named("JsonSafeLong").grouping_missing_value_placeholder).to eq MISSING_NUMERIC_PLACEHOLDER end it "returns nil for object types" do diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema_spec.rb index af1a8465e..2327ee1ad 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/schema_spec.rb @@ -16,7 +16,6 @@ class GraphQL define_schema do |schema| schema.scalar_type "_FieldSet" do |t| t.mapping type: "keyword" - t.json_schema type: "string" end schema.object_type "Widget" do |t| diff --git a/elasticgraph-health_check/spec/unit/elastic_graph/health_check/health_checker_spec.rb b/elasticgraph-health_check/spec/unit/elastic_graph/health_check/health_checker_spec.rb index f1ee584da..806dc7357 100644 --- a/elasticgraph-health_check/spec/unit/elastic_graph/health_check/health_checker_spec.rb +++ b/elasticgraph-health_check/spec/unit/elastic_graph/health_check/health_checker_spec.rb @@ -467,6 +467,7 @@ def build_health_checker(health_check:, latest: {}, index_definitions: nil, sche clients_by_name: datastore_clients_by_name, clock: class_double(::Time, now: now), schema_definition: schema_definition, + schema_definition_extension_modules: [], index_definitions: index_definitions, extension_settings: {"health_check" => health_check_settings}.compact ) diff --git a/elasticgraph-health_check/spec/unit/envoy_extension_spec.rb b/elasticgraph-health_check/spec/unit/envoy_extension_spec.rb index acd06b7b7..b4f1c4782 100644 --- a/elasticgraph-health_check/spec/unit/envoy_extension_spec.rb +++ b/elasticgraph-health_check/spec/unit/envoy_extension_spec.rb @@ -145,7 +145,7 @@ def process(http_method, url, with_configured_path_segment:, body: nil, cluster_ def build_graphql_for_path(http_path_segment) config = {http_path_segment: http_path_segment}.compact - schema_artifacts = generate_schema_artifacts do |schema| + schema_artifacts = generate_schema_artifacts(extension_modules: []) do |schema| schema.register_graphql_extension(EnvoyExtension, defined_at: "elastic_graph/health_check/envoy_extension", **config) schema.object_type "Widget" do |t| t.field "id", "ID" diff --git a/elasticgraph-indexer/spec/support/multiple_version_support.rb b/elasticgraph-indexer/spec/support/multiple_version_support.rb index f385d8cd4..9831a2174 100644 --- a/elasticgraph-indexer/spec/support/multiple_version_support.rb +++ b/elasticgraph-indexer/spec/support/multiple_version_support.rb @@ -6,6 +6,7 @@ # # frozen_string_literal: true +require "elastic_graph/json_ingestion/schema_definition/api_extension" require "elastic_graph/spec_support/schema_definition_helpers" module ElasticGraph @@ -15,7 +16,12 @@ class Indexer def build_indexer_with_multiple_schema_versions(schema_versions:) results_by_version = schema_versions.to_h do |json_schema_version, prior_def| - results = define_schema(schema_element_name_form: :snake_case, json_schema_version: json_schema_version, &prior_def) + results = define_schema( + schema_element_name_form: :snake_case, + json_schema_version: json_schema_version, + extension_modules: [JSONIngestion::SchemaDefinition::APIExtension], + &prior_def + ) [json_schema_version, results] end diff --git a/elasticgraph-indexer/spec/unit/elastic_graph/indexer/record_preparer_spec.rb b/elasticgraph-indexer/spec/unit/elastic_graph/indexer/record_preparer_spec.rb index 1ecc94fc3..bfea42d70 100644 --- a/elasticgraph-indexer/spec/unit/elastic_graph/indexer/record_preparer_spec.rb +++ b/elasticgraph-indexer/spec/unit/elastic_graph/indexer/record_preparer_spec.rb @@ -7,6 +7,7 @@ # frozen_string_literal: true require "elastic_graph/indexer/record_preparer" +require "elastic_graph/json_ingestion/schema_definition/api_extension" require "elastic_graph/spec_support/schema_definition_helpers" require "support/multiple_version_support" diff --git a/elasticgraph-json_ingestion/lib/elastic_graph/json_ingestion/schema_definition/factory_extension.rb b/elasticgraph-json_ingestion/lib/elastic_graph/json_ingestion/schema_definition/factory_extension.rb index 2bff39624..93f2ae09e 100644 --- a/elasticgraph-json_ingestion/lib/elastic_graph/json_ingestion/schema_definition/factory_extension.rb +++ b/elasticgraph-json_ingestion/lib/elastic_graph/json_ingestion/schema_definition/factory_extension.rb @@ -90,7 +90,7 @@ def new_scalar_type(name) extended_type.json_schema(**options) end - yield extended_type + yield extended_type if block_given? extended_type.finalize_json_schema_configuration! end end @@ -104,7 +104,7 @@ def new_scalar_indexing_field_type(scalar_type:) def new_type_with_subfields(schema_kind, name, wrapping_type:, field_factory:) super(schema_kind, name, wrapping_type: wrapping_type, field_factory: field_factory) do |type| extended_type = type.extend(SchemaElements::TypeWithSubfieldsExtension) # : ::ElasticGraph::SchemaDefinition::SchemaElements::TypeWithSubfields & SchemaElements::TypeWithSubfieldsExtension - yield extended_type + yield extended_type if block_given? end end diff --git a/elasticgraph-json_ingestion/spec/support/json_ingestion_schema_definition_helpers.rb b/elasticgraph-json_ingestion/spec/support/json_ingestion_schema_definition_helpers.rb new file mode 100644 index 000000000..1cae87905 --- /dev/null +++ b/elasticgraph-json_ingestion/spec/support/json_ingestion_schema_definition_helpers.rb @@ -0,0 +1,28 @@ +# Copyright 2024 - 2026 Block, Inc. +# +# Use of this source code is governed by an MIT-style +# license that can be found in the LICENSE file or at +# https://opensource.org/licenses/MIT. +# +# frozen_string_literal: true + +require "elastic_graph/json_ingestion/schema_definition/api_extension" +require "elastic_graph/spec_support/schema_definition_helpers" + +# Extends the shared "SchemaDefinitionHelpers" context to automatically apply this gem's +# `APIExtension` to every defined schema, since every spec in this gem exercises behavior +# provided by that extension. Additional extension modules can still be passed via +# `extension_modules:` and will be applied alongside it. +::RSpec.shared_context "JSONIngestionSchemaDefinitionHelpers" do + include_context "SchemaDefinitionHelpers" + + def define_schema_with_schema_elements(schema_elements, extension_modules: [], output: nil, **options, &block) + super( + schema_elements, + extension_modules: [::ElasticGraph::JSONIngestion::SchemaDefinition::APIExtension] | extension_modules, + output: output || log_device, + **options, + &block + ) + end +end diff --git a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/json_schema_with_metadata_spec.rb b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/json_schema_with_metadata_spec.rb index 021d71793..a116267d2 100644 --- a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/json_schema_with_metadata_spec.rb +++ b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/json_schema_with_metadata_spec.rb @@ -7,13 +7,13 @@ # frozen_string_literal: true require "elastic_graph/json_ingestion/schema_definition/indexing/json_schema_with_metadata" -require "elastic_graph/spec_support/schema_definition_helpers" +require "support/json_ingestion_schema_definition_helpers" module ElasticGraph module JSONIngestion::SchemaDefinition module Indexing ::RSpec.describe JSONSchemaWithMetadata do - include_context "SchemaDefinitionHelpers" + include_context "JSONIngestionSchemaDefinitionHelpers" it "ignores derived indexed types that do not show up in the JSON schema" do v1_json_schema = dump_versioned_json_schema do |schema| @@ -1056,7 +1056,6 @@ def metadata_for(json_schema, type, field) def define_schema(&schema_definition) super( schema_element_name_form: "snake_case", - extension_modules: [APIExtension], &schema_definition ) end diff --git a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/wrappers_spec.rb b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/wrappers_spec.rb index feb265303..8d1ed751a 100644 --- a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/wrappers_spec.rb +++ b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/indexing/wrappers_spec.rb @@ -11,13 +11,13 @@ require "elastic_graph/json_ingestion/schema_definition/indexing/field" require "elastic_graph/json_ingestion/schema_definition/indexing/field_reference" require "elastic_graph/json_ingestion/schema_definition/indexing/field_type/object" -require "elastic_graph/spec_support/schema_definition_helpers" +require "support/json_ingestion_schema_definition_helpers" require "support/json_schema_matcher" module ElasticGraph module JSONIngestion::SchemaDefinition ::RSpec.describe "JSON schema indexing wrappers" do - include_context "SchemaDefinitionHelpers" + include_context "JSONIngestionSchemaDefinitionHelpers" # `FieldReference#resolve` is a lazy reference: the referenced type need not exist when a field is # defined, only when artifacts are dumped. These two specs drive both outcomes (resolves / never @@ -45,7 +45,11 @@ module JSONIngestion::SchemaDefinition }) end - it "raises a clear error (rather than blowing up internally) for a field whose type never resolves" do + # `:dont_validate_graphql_schema` matters here: with `VALIDATE_GRAPHQL_SCHEMAS=1` (as on CI), the + # eager SDL validation would raise this error during GraphQL schema generation, before the JSON + # schema generation path exercises the wrapped `FieldReference#resolve` nil return that this + # example exists to cover. + it "raises a clear error (rather than blowing up internally) for a field whose type never resolves", :dont_validate_graphql_schema do # When a field references a type that is never defined, the wrapped `FieldReference#resolve` # returns `nil`. The schema definition machinery relies on that `nil` to detect the unresolvable # type and surface a helpful error instead of crashing. diff --git a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_field_metadata_spec.rb b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_field_metadata_spec.rb index 0ebfeafe0..b06ac7980 100644 --- a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_field_metadata_spec.rb +++ b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_field_metadata_spec.rb @@ -7,12 +7,12 @@ # frozen_string_literal: true require "elastic_graph/json_ingestion/schema_definition/indexing/json_schema_field_metadata" -require "elastic_graph/spec_support/schema_definition_helpers" +require "support/json_ingestion_schema_definition_helpers" module ElasticGraph module JSONIngestion::SchemaDefinition ::RSpec.describe "JSON schema field metadata generation" do - include_context "SchemaDefinitionHelpers" + include_context "JSONIngestionSchemaDefinitionHelpers" it "generates no field metadata for built-in scalar and enum types" do metadata_by_type_and_field_name = dump_metadata @@ -143,7 +143,6 @@ def dump_metadata(&schema_definition) def define_schema(&schema_definition) super( schema_element_name_form: "snake_case", - extension_modules: [APIExtension], &schema_definition ) end diff --git a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_pruner_spec.rb b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_pruner_spec.rb index 12bde76e8..44358aad2 100644 --- a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_pruner_spec.rb +++ b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_pruner_spec.rb @@ -8,12 +8,12 @@ require "elastic_graph/constants" require "elastic_graph/json_ingestion/schema_definition/json_schema_pruner" -require "elastic_graph/spec_support/schema_definition_helpers" +require "support/json_ingestion_schema_definition_helpers" module ElasticGraph module JSONIngestion::SchemaDefinition RSpec.describe JSONSchemaPruner, :capture_logs do - include_context "SchemaDefinitionHelpers" + include_context "JSONIngestionSchemaDefinitionHelpers" describe ".prune" do subject { described_class.prune(schema) } diff --git a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_spec.rb b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_spec.rb index 1c964801d..507eaef43 100644 --- a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_spec.rb +++ b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/json_schema_spec.rb @@ -8,14 +8,13 @@ require "elastic_graph/constants" require "elastic_graph/errors" -require "elastic_graph/json_ingestion/schema_definition/api_extension" -require "elastic_graph/spec_support/schema_definition_helpers" +require "support/json_ingestion_schema_definition_helpers" require "support/json_schema_matcher" module ElasticGraph module JSONIngestion::SchemaDefinition ::RSpec.describe "JSON schema generation" do - include_context "SchemaDefinitionHelpers" + include_context "JSONIngestionSchemaDefinitionHelpers" json_schema_id = {"allOf" => [{"$ref" => "#/$defs/ID"}, {"maxLength" => DEFAULT_MAX_KEYWORD_LENGTH}]} json_schema_float = {"$ref" => "#/$defs/Float"} json_schema_integer = {"$ref" => "#/$defs/Int"} @@ -113,10 +112,7 @@ module JSONIngestion::SchemaDefinition it "configures built-in scalar JSON schema before user schema blocks are evaluated" do json_schema_options_in_schema_block = nil - define_schema( - schema_element_name_form: "snake_case", - extension_modules: [JSONIngestion::SchemaDefinition::APIExtension] - ) do |s| + define_schema(schema_element_name_form: "snake_case") do |s| json_schema_options_in_schema_block = s.state.scalar_types_by_name.fetch("String").json_schema_options.dup s.object_type "Widget" do |t| diff --git a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/schema_elements/scalar_type_extension_spec.rb b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/schema_elements/scalar_type_extension_spec.rb index aeabea81d..8497479c6 100644 --- a/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/schema_elements/scalar_type_extension_spec.rb +++ b/elasticgraph-json_ingestion/spec/unit/elastic_graph/json_ingestion/schema_definition/schema_elements/scalar_type_extension_spec.rb @@ -8,15 +8,16 @@ require "elastic_graph/constants" require "elastic_graph/errors" +require "elastic_graph/json_ingestion/schema_definition/api_extension" require "elastic_graph/json_ingestion/schema_definition/schema_elements/scalar_type_extension" -require "elastic_graph/spec_support/schema_definition_helpers" +require "support/json_ingestion_schema_definition_helpers" module ElasticGraph module JSONIngestion module SchemaDefinition module SchemaElements RSpec.describe ScalarTypeExtension do - include_context "SchemaDefinitionHelpers" + include_context "JSONIngestionSchemaDefinitionHelpers" it "requires custom scalar types to declare their JSON schema representation" do expect { @@ -28,145 +29,174 @@ module SchemaElements }.to raise_error Errors::SchemaError, a_string_including("BigInt", "lacks `json_schema`") end - describe "#grouping_missing_value_placeholder" do - it "infers a numeric missing-value placeholder for JSON-safe unsigned_long scalars with custom coercion" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "unsigned_long", - type: "integer", - maximum: JSON_SAFE_LONG_MAX - ) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + it "extends schema elements created without customization blocks" do + api = build_api + api.enum_type "EmptyEnum" + api.interface_type "EmptyInterface" + direct_type_with_subfields = api.factory.new_type_with_subfields( + :object, + "DirectObject", + wrapping_type: nil, + field_factory: api.factory.method(:new_field) + ) + + # An enum's derived GraphQL types are built from a derived scalar twin, which can only be + # built if `EnumTypeExtension` configured the twin's `json_schema`; otherwise building it + # raises a "lacks `json_schema`" error. + expect { + api.state.enum_types_by_name.fetch("EmptyEnum").derived_graphql_types + }.not_to raise_error - expect(grouping_missing_value_placeholder).to eq(MISSING_NUMERIC_PLACEHOLDER) - end + # `json_schema` is only available on types extended with `TypeWithSubfieldsExtension`. + interface_type = api.state.object_types_by_name.fetch("EmptyInterface") + interface_type.json_schema minProperties: 1 + expect(interface_type.json_schema_options).to eq({minProperties: 1}) - it "does not infer a numeric missing-value placeholder for unsigned_long scalars outside the JSON-safe range" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "unsigned_long", - type: "integer", - maximum: JSON_SAFE_LONG_MAX + 1 - ) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + direct_type_with_subfields.json_schema minProperties: 2 + expect(direct_type_with_subfields.json_schema_options).to eq({minProperties: 2}) - expect(grouping_missing_value_placeholder).to eq(nil) + expect { + build_api.scalar_type "BigInt" + }.to raise_error Errors::SchemaError, a_string_including("BigInt", "lacks `json_schema`") + end + + it "infers a numeric missing-value placeholder for JSON-safe unsigned_long scalars with custom coercion" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "unsigned_long", + type: "integer", + maximum: JSON_SAFE_LONG_MAX + ) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for JSON-safe unsigned_long scalars with the default coercion adapter (which would not coerce floats back to integers)" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "unsigned_long", - type: "integer", - maximum: JSON_SAFE_LONG_MAX - ) + expect(grouping_missing_value_placeholder).to eq(MISSING_NUMERIC_PLACEHOLDER) + end - expect(grouping_missing_value_placeholder).to eq(nil) + it "does not infer a numeric missing-value placeholder for unsigned_long scalars outside the JSON-safe range" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "unsigned_long", + type: "integer", + maximum: JSON_SAFE_LONG_MAX + 1 + ) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for unsigned_long scalars when no maximum is specified" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for("unsigned_long", type: "integer") do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + expect(grouping_missing_value_placeholder).to eq(nil) + end - expect(grouping_missing_value_placeholder).to eq(nil) - end + it "does not infer a placeholder for JSON-safe unsigned_long scalars with the default coercion adapter (which would not coerce floats back to integers)" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "unsigned_long", + type: "integer", + maximum: JSON_SAFE_LONG_MAX + ) - it "infers a numeric missing-value placeholder for long scalars exactly at the JSON-safe boundaries with custom coercion" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "long", - type: "integer", - minimum: JSON_SAFE_LONG_MIN, - maximum: JSON_SAFE_LONG_MAX - ) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + expect(grouping_missing_value_placeholder).to eq(nil) + end - expect(grouping_missing_value_placeholder).to eq(MISSING_NUMERIC_PLACEHOLDER) + it "does not infer a placeholder for unsigned_long scalars when no maximum is specified" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for("unsigned_long", type: "integer") do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for JSON-safe long scalars with the default coercion adapter" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "long", - type: "integer", - minimum: JSON_SAFE_LONG_MIN, - maximum: JSON_SAFE_LONG_MAX - ) + expect(grouping_missing_value_placeholder).to eq(nil) + end - expect(grouping_missing_value_placeholder).to eq(nil) + it "infers a numeric missing-value placeholder for long scalars exactly at the JSON-safe boundaries with custom coercion" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "long", + type: "integer", + minimum: JSON_SAFE_LONG_MIN, + maximum: JSON_SAFE_LONG_MAX + ) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for long scalars when the minimum is one below the JSON-safe range" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "long", - type: "integer", - minimum: JSON_SAFE_LONG_MIN - 1, - maximum: JSON_SAFE_LONG_MAX - ) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + expect(grouping_missing_value_placeholder).to eq(MISSING_NUMERIC_PLACEHOLDER) + end - expect(grouping_missing_value_placeholder).to eq(nil) + it "does not infer a placeholder for JSON-safe long scalars with the default coercion adapter" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "long", + type: "integer", + minimum: JSON_SAFE_LONG_MIN, + maximum: JSON_SAFE_LONG_MAX + ) + + expect(grouping_missing_value_placeholder).to eq(nil) + end + + it "does not infer a placeholder for long scalars when the minimum is one below the JSON-safe range" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "long", + type: "integer", + minimum: JSON_SAFE_LONG_MIN - 1, + maximum: JSON_SAFE_LONG_MAX + ) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for long scalars when the maximum is one above the JSON-safe range" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( - "long", - type: "integer", - minimum: JSON_SAFE_LONG_MIN, - maximum: JSON_SAFE_LONG_MAX + 1 - ) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + expect(grouping_missing_value_placeholder).to eq(nil) + end - expect(grouping_missing_value_placeholder).to eq(nil) + it "does not infer a placeholder for long scalars when the maximum is one above the JSON-safe range" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for( + "long", + type: "integer", + minimum: JSON_SAFE_LONG_MIN, + maximum: JSON_SAFE_LONG_MAX + 1 + ) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for long scalars when only one bound is specified (the other defaults to the LongString range)" do - only_min = grouping_missing_value_placeholder_for("long", type: "integer", minimum: 0) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + expect(grouping_missing_value_placeholder).to eq(nil) + end - only_max = grouping_missing_value_placeholder_for("long", type: "integer", maximum: 1000) do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + it "does not infer a placeholder for long scalars when only one bound is specified (the other defaults to the LongString range)" do + only_min = grouping_missing_value_placeholder_for("long", type: "integer", minimum: 0) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path + end - expect(only_min).to eq(nil) - expect(only_max).to eq(nil) + only_max = grouping_missing_value_placeholder_for("long", type: "integer", maximum: 1000) do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "does not infer a placeholder for long scalars when no bounds are specified" do - grouping_missing_value_placeholder = grouping_missing_value_placeholder_for("long", type: "integer") do |type| - type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path - end + expect(only_min).to eq(nil) + expect(only_max).to eq(nil) + end - expect(grouping_missing_value_placeholder).to eq(nil) + it "does not infer a placeholder for long scalars when no bounds are specified" do + grouping_missing_value_placeholder = grouping_missing_value_placeholder_for("long", type: "integer") do |type| + type.coerce_with "ExampleScalarCoercionAdapter", defined_at: scalar_coercion_adapter_path end - it "has the expected placeholder for each built-in scalar type, including the JSON-safe-range-aware `JsonSafeLong` inference" do - results = define_schema(schema_element_name_form: "snake_case") { |schema| } - built_in_scalars = results.state.scalar_types_by_name.keys - scalar_types_by_name = results.runtime_metadata.scalar_types_by_name + expect(grouping_missing_value_placeholder).to eq(nil) + end - placeholders_by_scalar_type = built_in_scalars.to_h do |scalar_type| - [scalar_type, scalar_types_by_name.fetch(scalar_type).grouping_missing_value_placeholder] - end + it "has the expected placeholder for each built-in scalar type, including the JSON-safe-range-aware `JsonSafeLong` inference" do + results = define_schema(schema_element_name_form: "snake_case") { |schema| } + built_in_scalars = results.state.scalar_types_by_name.keys + scalar_types_by_name = results.runtime_metadata.scalar_types_by_name - expect(placeholders_by_scalar_type).to eq({ - "Boolean" => nil, - "Cursor" => MISSING_STRING_PLACEHOLDER, - "Date" => nil, - "DateTime" => nil, - "Float" => MISSING_NUMERIC_PLACEHOLDER, - "ID" => MISSING_STRING_PLACEHOLDER, - "Int" => MISSING_NUMERIC_PLACEHOLDER, # GraphQL automatically coerces Int values - "JsonSafeLong" => MISSING_NUMERIC_PLACEHOLDER, # custom coercion adapter coerces floats back to integers - "LocalTime" => nil, - "LongString" => nil, # outside of the JSON safe range. - "String" => MISSING_STRING_PLACEHOLDER, - "TimeZone" => MISSING_STRING_PLACEHOLDER, - "Untyped" => MISSING_STRING_PLACEHOLDER - }) + placeholders_by_scalar_type = built_in_scalars.to_h do |scalar_type| + [scalar_type, scalar_types_by_name.fetch(scalar_type).grouping_missing_value_placeholder] end + + expect(placeholders_by_scalar_type).to eq({ + "Boolean" => nil, + "Cursor" => MISSING_STRING_PLACEHOLDER, + "Date" => nil, + "DateTime" => nil, + "Float" => MISSING_NUMERIC_PLACEHOLDER, + "ID" => MISSING_STRING_PLACEHOLDER, + "Int" => MISSING_NUMERIC_PLACEHOLDER, # GraphQL automatically coerces Int values + "JsonSafeLong" => MISSING_NUMERIC_PLACEHOLDER, # custom coercion adapter coerces floats back to integers + "LocalTime" => nil, + "LongString" => nil, # outside of the JSON safe range. + "String" => MISSING_STRING_PLACEHOLDER, + "TimeZone" => MISSING_STRING_PLACEHOLDER, + "Untyped" => MISSING_STRING_PLACEHOLDER + }) end def grouping_missing_value_placeholder_for(mapping_type, **json_schema_options) @@ -186,6 +216,16 @@ def scalar_coercion_adapter_path # when one worker runs multiple suites. "elastic_graph/spec_support/example_extensions/scalar_coercion_adapter" end + + def build_api + schema_elements = SchemaArtifacts::RuntimeMetadata::SchemaElementNames.new(form: "snake_case") + ::ElasticGraph::SchemaDefinition::API.new( + schema_elements, + true, + extension_modules: [APIExtension], + output: log_device + ) + end end end end diff --git a/elasticgraph-query_interceptor/spec/unit/elastic_graph/query_interceptor/graphql_extension_spec.rb b/elasticgraph-query_interceptor/spec/unit/elastic_graph/query_interceptor/graphql_extension_spec.rb index 8407e57c4..cf61aa6ba 100644 --- a/elasticgraph-query_interceptor/spec/unit/elastic_graph/query_interceptor/graphql_extension_spec.rb +++ b/elasticgraph-query_interceptor/spec/unit/elastic_graph/query_interceptor/graphql_extension_spec.rb @@ -170,7 +170,7 @@ def expect_configured_interceptors(graphql) end def generate_schema_artifacts - super do |schema| + super(extension_modules: []) do |schema| yield schema # Ensure there's at least one indexed type defined to avoid GraphQL validation errors. diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb index 9dcc2533a..5a2402501 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb @@ -79,8 +79,10 @@ def define_schema_with_schema_elements( # exists when an extension that implements JSON schema generation (such as # `elasticgraph-json_ingestion`) is loaded; without one there is no JSON schema version to set. if !json_schema_version.nil? && api.respond_to?(:json_schema_version) + # :nocov: -- only entered when a JSON schema extension is loaded, which is not the case in elasticgraph-schema_definition's tests. versioned_api = api # : untyped versioned_api.json_schema_version(json_schema_version) if versioned_api.state.json_schema_version.nil? + # :nocov: end # :nocov: -- the else branch and code past this aren't used by tests in elasticgraph-schema_definition. diff --git a/spec_support/lib/elastic_graph/spec_support/builds_datastore_core.rb b/spec_support/lib/elastic_graph/spec_support/builds_datastore_core.rb index df5e50e8b..d88fb39e0 100644 --- a/spec_support/lib/elastic_graph/spec_support/builds_datastore_core.rb +++ b/spec_support/lib/elastic_graph/spec_support/builds_datastore_core.rb @@ -30,6 +30,7 @@ def build_datastore_core( clusters: nil, schema_artifacts_directory: nil, schema_artifacts: nil, + schema_definition_extension_modules: [], datastore_backend: nil, reload_schema_artifacts: false, **config_overrides, @@ -61,6 +62,7 @@ def build_datastore_core( derived_type_name_formats: derived_type_name_formats, type_name_overrides: type_name_overrides, enum_value_overrides_by_type: enum_value_overrides_by_type, + extension_modules: schema_definition_extension_modules, reload_schema_artifacts: reload_schema_artifacts, &schema_definition ) diff --git a/spec_support/lib/elastic_graph/spec_support/builds_indexer.rb b/spec_support/lib/elastic_graph/spec_support/builds_indexer.rb index 23fa72092..33ae7fbf3 100644 --- a/spec_support/lib/elastic_graph/spec_support/builds_indexer.rb +++ b/spec_support/lib/elastic_graph/spec_support/builds_indexer.rb @@ -21,11 +21,18 @@ def build_indexer( datastore_router: nil, clock: nil, monotonic_clock: nil, + schema_definition_extension_modules: nil, **datastore_core_options, &customize_datastore_config ) + datastore_core ||= build_datastore_core( + schema_definition_extension_modules: schema_definition_extension_modules || default_indexer_schema_definition_extension_modules, + **datastore_core_options, + &customize_datastore_config + ) + Indexer.new( - datastore_core: datastore_core || build_datastore_core(**datastore_core_options, &customize_datastore_config), + datastore_core: datastore_core, config: Indexer::Config.new( latency_slo_thresholds_by_timestamp_in_ms: latency_slo_thresholds_by_timestamp_in_ms, skip_derived_indexing_type_updates: skip_derived_indexing_type_updates @@ -35,6 +42,17 @@ def build_indexer( monotonic_clock: monotonic_clock ) end + + private + + # The indexer can only ingest JSON events today, so artifacts generated for an indexer must + # include the JSON schemas; this is the one spec builder that opts into the extension by default. + # The require is lazy so that gems whose bundles do not include `elasticgraph-json_ingestion` + # can still use this builder with an externally built `datastore_core:`. + def default_indexer_schema_definition_extension_modules + require "elastic_graph/json_ingestion/schema_definition/api_extension" + [JSONIngestion::SchemaDefinition::APIExtension] + end end RSpec.configure do |c| diff --git a/spec_support/lib/elastic_graph/spec_support/schema_definition_helpers.rb b/spec_support/lib/elastic_graph/spec_support/schema_definition_helpers.rb index d279fd460..de63f4e7d 100644 --- a/spec_support/lib/elastic_graph/spec_support/schema_definition_helpers.rb +++ b/spec_support/lib/elastic_graph/spec_support/schema_definition_helpers.rb @@ -8,49 +8,22 @@ require "elastic_graph/schema_definition/test_support" -module ElasticGraph - module SpecSupport - DEFAULT_SCHEMA_DEFINITION_EXTENSION_MODULES = begin - require "elastic_graph/json_ingestion/schema_definition/api_extension" - [::ElasticGraph::JSONIngestion::SchemaDefinition::APIExtension] - rescue LoadError => e - # :nocov: -- per-gem spec bundles may not include the optional `elasticgraph-json_ingestion` gem. - raise unless e.path == "elastic_graph/json_ingestion/schema_definition/api_extension" - - [] - # :nocov: - end.freeze - end -end - # Combines `:capture_logs` with `ElasicGraph::SchemaDefinition::TestSupport` in order # to silence log output and fail if any tests result in logged warnings. ::RSpec.shared_context "SchemaDefinitionHelpers", :capture_logs do include ::ElasticGraph::SchemaDefinition::TestSupport - # Defaults `extension_modules` and `output` for tests; all other options are forwarded to - # `TestSupport` unchanged. `output` must be handled with `||` (rather than a keyword default) - # because `TestSupport#define_schema` passes `output: nil` explicitly when no output is given. - def define_schema(extension_modules: default_schema_definition_extension_modules, output: nil, **options, &block) - super( - extension_modules: extension_modules, - output: output || log_device, - **options, - &block - ) - end - - def define_schema_with_schema_elements(schema_elements, extension_modules: default_schema_definition_extension_modules, output: nil, **options, &block) - super( - schema_elements, - extension_modules: extension_modules, - output: output || log_device, - **options, - &block - ) + # Defaults `output` for tests; all other options are forwarded to `TestSupport` unchanged. + # `output` must be handled with `||` (rather than a keyword default) because + # `TestSupport#define_schema` passes `output: nil` explicitly when no output is given. + # + # Note: schema definition extension modules (such as the one from `elasticgraph-json_ingestion`) + # are intentionally not defaulted; specs that need an extension must opt in explicitly. + def define_schema(output: nil, **options, &block) + super(output: output || log_device, **options, &block) end - def default_schema_definition_extension_modules - ::ElasticGraph::SpecSupport::DEFAULT_SCHEMA_DEFINITION_EXTENSION_MODULES.dup + def define_schema_with_schema_elements(schema_elements, output: nil, **options, &block) + super(schema_elements, output: output || log_device, **options, &block) end end diff --git a/spec_support/spec_helper.rb b/spec_support/spec_helper.rb index 655e16663..f76e05b0d 100644 --- a/spec_support/spec_helper.rb +++ b/spec_support/spec_helper.rb @@ -356,7 +356,10 @@ def without_vcr end # :nocov: + # `extension_modules` intentionally defaults to none: specs must opt in explicitly to schema + # definition extensions (such as the one from `elasticgraph-json_ingestion`). def generate_schema_artifacts( + extension_modules: [], schema_element_name_form: :snake_case, schema_element_name_overrides: {}, derived_type_name_formats: {}, @@ -365,9 +368,15 @@ def generate_schema_artifacts( reload_schema_artifacts: false ) require "elastic_graph/schema_definition/test_support" - require "elastic_graph/spec_support/schema_definition_helpers" require "stringio" + unless block_given? + # When no block is given we load the repository's main test schema (`config/schema.rb`), + # which uses the JSON ingestion schema definition DSL, so it requires this extension. + require "elastic_graph/json_ingestion/schema_definition/api_extension" + extension_modules += [JSONIngestion::SchemaDefinition::APIExtension] + end + output = ::StringIO.new # to silence warnings. ::ElasticGraph::SchemaDefinition::TestSupport.define_schema( schema_element_name_form: schema_element_name_form, @@ -375,7 +384,7 @@ def generate_schema_artifacts( derived_type_name_formats: derived_type_name_formats, type_name_overrides: type_name_overrides, enum_value_overrides_by_type: enum_value_overrides_by_type, - extension_modules: ::ElasticGraph::SpecSupport::DEFAULT_SCHEMA_DEFINITION_EXTENSION_MODULES.dup, + extension_modules: extension_modules, reload_schema_artifacts: reload_schema_artifacts, output: output ) do |schema|