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 eac218050..3843513a4 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 9956e95e9..e7b3c5304 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" @@ -91,6 +92,9 @@ def self.with_both_casing_forms(&block) schema_element_name_form: :camelCase, derived_type_name_formats: derived_type_name_formats, 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 90ccfe347..e44d8d0e5 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 7cf193e1d..ec1e962a7 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/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 c8327661f..9a6b878c6 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 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 364dfe2ee..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 { 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 bca599c27..0edb7c041 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 @@ -29,6 +29,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, @@ -59,6 +60,7 @@ def build_datastore_core( schema_element_name_overrides: schema_element_name_overrides, derived_type_name_formats: derived_type_name_formats, 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 6de600e91..86191369f 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: {}, @@ -364,16 +367,22 @@ 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, schema_element_name_overrides: schema_element_name_overrides, derived_type_name_formats: derived_type_name_formats, 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|