| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.druid.sql.calcite.util; |
| |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.inject.Binder; |
| import com.google.inject.Injector; |
| import com.google.inject.Module; |
| import com.google.inject.Provides; |
| import org.apache.druid.guice.DruidInjectorBuilder; |
| import org.apache.druid.guice.ExpressionModule; |
| import org.apache.druid.guice.LazySingleton; |
| import org.apache.druid.guice.SegmentWranglerModule; |
| import org.apache.druid.guice.StartupInjectorBuilder; |
| import org.apache.druid.initialization.CoreInjectorBuilder; |
| import org.apache.druid.initialization.DruidModule; |
| import org.apache.druid.initialization.ServiceInjectorBuilder; |
| import org.apache.druid.java.util.common.RE; |
| import org.apache.druid.java.util.common.io.Closer; |
| import org.apache.druid.math.expr.ExprMacroTable; |
| import org.apache.druid.query.GlobalTableDataSource; |
| import org.apache.druid.query.QueryRunnerFactoryConglomerate; |
| import org.apache.druid.query.lookup.LookupExtractorFactoryContainerProvider; |
| import org.apache.druid.query.topn.TopNQueryConfig; |
| import org.apache.druid.segment.DefaultColumnFormatConfig; |
| import org.apache.druid.segment.join.JoinableFactoryWrapper; |
| import org.apache.druid.server.QueryLifecycle; |
| import org.apache.druid.server.QueryLifecycleFactory; |
| import org.apache.druid.server.QueryStackTests; |
| import org.apache.druid.server.SpecificSegmentsQuerySegmentWalker; |
| import org.apache.druid.server.security.AuthConfig; |
| import org.apache.druid.server.security.AuthorizerMapper; |
| import org.apache.druid.sql.SqlStatementFactory; |
| import org.apache.druid.sql.calcite.TempDirProducer; |
| import org.apache.druid.sql.calcite.aggregation.SqlAggregationModule; |
| import org.apache.druid.sql.calcite.planner.CalciteRulesManager; |
| import org.apache.druid.sql.calcite.planner.CatalogResolver; |
| import org.apache.druid.sql.calcite.planner.DruidOperatorTable; |
| import org.apache.druid.sql.calcite.planner.PlannerConfig; |
| import org.apache.druid.sql.calcite.planner.PlannerFactory; |
| import org.apache.druid.sql.calcite.rule.ExtensionCalciteRuleProvider; |
| import org.apache.druid.sql.calcite.run.NativeSqlEngine; |
| import org.apache.druid.sql.calcite.run.SqlEngine; |
| import org.apache.druid.sql.calcite.schema.DruidSchemaCatalog; |
| import org.apache.druid.sql.calcite.schema.DruidSchemaManager; |
| import org.apache.druid.sql.calcite.schema.NoopDruidSchemaManager; |
| import org.apache.druid.sql.calcite.view.DruidViewMacroFactory; |
| import org.apache.druid.sql.calcite.view.InProcessViewManager; |
| import org.apache.druid.sql.calcite.view.ViewManager; |
| import org.apache.druid.timeline.DataSegment; |
| |
| import java.io.Closeable; |
| import java.io.IOException; |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| /** |
| * Builds the infrastructure needed to run Calcite tests. Building splits into |
| * two parts: a constant part and a per-test part. The constant part includes |
| * the congolmerate and walker (that is, the implementation of the test data), |
| * while the per-query part includes the schema, planner factory and SQL |
| * statement factory. The key reason for the split is that the per-test part |
| * depends on the value of the {@link PlannerConfig} object, which varies between |
| * tests. |
| * <p> |
| * The builder accepts the injector to use. "Calcite tests" use the injector |
| * defined in {@link CalciteTests#INJECTOR}, while other tests can pass in the |
| * preferred injector. |
| * <p> |
| * The framework allows the test to customize many of the framework components. |
| * Since those components tend to depend on other framework components, we use |
| * an indirection, {@link SqlTestFramework.QueryComponentSupplier QueryComponentSupplier} |
| * to build those components. The methods of this interface match the methods |
| * in @link org.apache.druid.sql.calcite.BaseCalciteQueryTest BaseCalciteQueryTest} |
| * so that those tests can customize the framework just by overriding methods. |
| * (This was done to maintain backward compatibility with earlier versions of the |
| * code.) Other tests can implement {@code QueryComponentSupplier} directly by |
| * extending {@link SqlTestFramework.StandardComponentSupplier StandardComponentSupplier}. |
| * <p> |
| * The framework should be built once per test class (not once per test method.) |
| * Then, for each planner setup, call |
| * {@link #plannerFixture(PlannerConfig, AuthConfig)} |
| * to get a {@link PlannerFixture} with a view manager and planner factory. Call |
| * {@link PlannerFixture#statementFactory()} to |
| * obtain a the test-specific planner and wrapper classes for that test. After |
| * that, tests use the various SQL statement classes to run tests. For tests |
| * based on {@code BaseCalciteQueryTest}, the statements are wrapped by the |
| * various {@code testQuery()} methods. |
| * <p> |
| * For tests that use non-standard views, first create the {@code PlannerFixture}, |
| * populate the views, then use the {@code QueryTestBuilder} directly, passing in |
| * the {@code PlannerFixture} with views populated. |
| * <p> |
| * The framework holds on to the framework components. You can obtain the injector, |
| * object mapper and other items by calling the various methods. The objects |
| * are those created by the provided injector, or in this class, using objects |
| * from that injector. |
| */ |
| public class SqlTestFramework |
| { |
| /** |
| * Declares which {@link QueryComponentSupplier} must be used for the class. |
| */ |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target({ElementType.TYPE}) |
| public @interface SqlTestFrameWorkModule |
| { |
| Class<? extends QueryComponentSupplier> value(); |
| } |
| |
| /** |
| * Interface to provide various framework components. Extend to customize, |
| * use {@link StandardComponentSupplier} for the "standard" components. |
| * <p> |
| * Note that the methods here are named to match methods that already |
| * exist in {@code BaseCalciteQueryTest}. Any changes here will impact that |
| * base class, and possibly many test cases that extend that class. |
| */ |
| public interface QueryComponentSupplier extends Closeable |
| { |
| /** |
| * Gather properties to be used within tests. Particularly useful when choosing |
| * among aggregator implementations: avoids the need to copy/paste code to select |
| * the desired implementation. |
| */ |
| void gatherProperties(Properties properties); |
| |
| /** |
| * Configure modules needed for tests. This is the preferred way to configure |
| * Jackson: include the production module in this method that includes the |
| * required Jackson configuration. |
| */ |
| void configureGuice(DruidInjectorBuilder builder); |
| |
| QueryRunnerFactoryConglomerate createCongolmerate( |
| Builder builder, |
| Closer closer |
| ); |
| |
| SpecificSegmentsQuerySegmentWalker createQuerySegmentWalker( |
| QueryRunnerFactoryConglomerate conglomerate, |
| JoinableFactoryWrapper joinableFactory, |
| Injector injector |
| ); |
| |
| SqlEngine createEngine( |
| QueryLifecycleFactory qlf, |
| ObjectMapper objectMapper, |
| Injector injector |
| ); |
| |
| default CatalogResolver createCatalogResolver() |
| { |
| return CatalogResolver.NULL_RESOLVER; |
| } |
| |
| /** |
| * Configure the JSON mapper. |
| * |
| * @see #configureGuice(DruidInjectorBuilder) for the preferred solution. |
| */ |
| void configureJsonMapper(ObjectMapper mapper); |
| |
| JoinableFactoryWrapper createJoinableFactoryWrapper(LookupExtractorFactoryContainerProvider lookupProvider); |
| |
| void finalizeTestFramework(SqlTestFramework sqlTestFramework); |
| |
| PlannerComponentSupplier getPlannerComponentSupplier(); |
| } |
| |
| public interface PlannerComponentSupplier |
| { |
| Set<ExtensionCalciteRuleProvider> extensionCalciteRules(); |
| |
| ViewManager createViewManager(); |
| |
| void populateViews(ViewManager viewManager, PlannerFactory plannerFactory); |
| |
| DruidSchemaManager createSchemaManager(); |
| |
| void finalizePlanner(PlannerFixture plannerFixture); |
| } |
| |
| /** |
| * Provides a "standard" set of query components, where "standard" just means |
| * those you would get if you used {@code BaseCalciteQueryTest} with no |
| * customization. {@code BaseCalciteQueryTest} uses this class to provide those |
| * standard components. |
| */ |
| public static class StandardComponentSupplier implements QueryComponentSupplier |
| { |
| protected final TempDirProducer tempDirProducer; |
| private final PlannerComponentSupplier plannerComponentSupplier; |
| |
| public StandardComponentSupplier( |
| final TempDirProducer tempDirProducer |
| ) |
| { |
| this.tempDirProducer = tempDirProducer; |
| this.plannerComponentSupplier = buildPlannerComponentSupplier(); |
| } |
| |
| /** |
| * Build the {@link PlannerComponentSupplier}. |
| * |
| * Implementations may override how this is being built. |
| */ |
| protected PlannerComponentSupplier buildPlannerComponentSupplier() |
| { |
| return new StandardPlannerComponentSupplier(); |
| } |
| |
| @Override |
| public void gatherProperties(Properties properties) |
| { |
| } |
| |
| @Override |
| public void configureGuice(DruidInjectorBuilder builder) |
| { |
| } |
| |
| @Override |
| public QueryRunnerFactoryConglomerate createCongolmerate( |
| Builder builder, |
| Closer resourceCloser |
| ) |
| { |
| if (builder.mergeBufferCount == 0) { |
| return QueryStackTests.createQueryRunnerFactoryConglomerate( |
| resourceCloser, |
| () -> builder.minTopNThreshold |
| ); |
| } else { |
| return QueryStackTests.createQueryRunnerFactoryConglomerate( |
| resourceCloser, |
| QueryStackTests.getProcessingConfig(builder.mergeBufferCount) |
| ); |
| } |
| } |
| |
| @Override |
| public SpecificSegmentsQuerySegmentWalker createQuerySegmentWalker( |
| final QueryRunnerFactoryConglomerate conglomerate, |
| final JoinableFactoryWrapper joinableFactory, |
| final Injector injector |
| ) |
| { |
| return TestDataBuilder.createMockWalker( |
| injector, |
| conglomerate, |
| tempDirProducer.newTempFolder("segments"), |
| QueryStackTests.DEFAULT_NOOP_SCHEDULER, |
| joinableFactory |
| ); |
| } |
| |
| @Override |
| public SqlEngine createEngine( |
| QueryLifecycleFactory qlf, |
| ObjectMapper objectMapper, |
| Injector injector |
| ) |
| { |
| return new NativeSqlEngine( |
| qlf, |
| objectMapper |
| ); |
| } |
| |
| @Override |
| public void configureJsonMapper(ObjectMapper mapper) |
| { |
| } |
| |
| @Override |
| public JoinableFactoryWrapper createJoinableFactoryWrapper(LookupExtractorFactoryContainerProvider lookupProvider) |
| { |
| return new JoinableFactoryWrapper( |
| QueryStackTests.makeJoinableFactoryFromDefault( |
| lookupProvider, |
| ImmutableSet.of(TestDataBuilder.CUSTOM_ROW_TABLE_JOINABLE), |
| ImmutableMap.of(TestDataBuilder.CUSTOM_ROW_TABLE_JOINABLE.getClass(), GlobalTableDataSource.class) |
| ) |
| ); |
| } |
| |
| @Override |
| public void finalizeTestFramework(SqlTestFramework sqlTestFramework) |
| { |
| } |
| |
| @Override |
| public PlannerComponentSupplier getPlannerComponentSupplier() |
| { |
| return plannerComponentSupplier; |
| } |
| |
| @Override |
| public void close() throws IOException |
| { |
| tempDirProducer.close(); |
| } |
| } |
| |
| public static class StandardPlannerComponentSupplier implements PlannerComponentSupplier |
| { |
| @Override |
| public Set<ExtensionCalciteRuleProvider> extensionCalciteRules() |
| { |
| return ImmutableSet.of(); |
| } |
| |
| @Override |
| public ViewManager createViewManager() |
| { |
| return new InProcessViewManager(DRUID_VIEW_MACRO_FACTORY); |
| } |
| |
| @Override |
| public void populateViews(ViewManager viewManager, PlannerFactory plannerFactory) |
| { |
| viewManager.createView( |
| plannerFactory, |
| "aview", |
| "SELECT SUBSTRING(dim1, 1, 1) AS dim1_firstchar FROM foo WHERE dim2 = 'a'" |
| ); |
| |
| viewManager.createView( |
| plannerFactory, |
| "bview", |
| "SELECT COUNT(*) FROM druid.foo\n" |
| + "WHERE __time >= CURRENT_TIMESTAMP + INTERVAL '1' DAY AND __time < TIMESTAMP '2002-01-01 00:00:00'" |
| ); |
| |
| viewManager.createView( |
| plannerFactory, |
| "cview", |
| "SELECT SUBSTRING(bar.dim1, 1, 1) AS dim1_firstchar, bar.dim2 as dim2, dnf.l2 as l2\n" |
| + "FROM (SELECT * from foo WHERE dim2 = 'a') as bar INNER JOIN druid.numfoo dnf ON bar.dim2 = dnf.dim2" |
| ); |
| |
| viewManager.createView( |
| plannerFactory, |
| "dview", |
| "SELECT SUBSTRING(dim1, 1, 1) AS numfoo FROM foo WHERE dim2 = 'a'" |
| ); |
| |
| viewManager.createView( |
| plannerFactory, |
| "forbiddenView", |
| "SELECT __time, SUBSTRING(dim1, 1, 1) AS dim1_firstchar, dim2 FROM foo WHERE dim2 = 'a'" |
| ); |
| |
| viewManager.createView( |
| plannerFactory, |
| "restrictedView", |
| "SELECT __time, dim1, dim2, m1 FROM druid.forbiddenDatasource WHERE dim2 = 'a'" |
| ); |
| |
| viewManager.createView( |
| plannerFactory, |
| "invalidView", |
| "SELECT __time, dim1, dim2, m1 FROM druid.invalidDatasource WHERE dim2 = 'a'" |
| ); |
| } |
| |
| @Override |
| public DruidSchemaManager createSchemaManager() |
| { |
| return new NoopDruidSchemaManager(); |
| } |
| |
| @Override |
| public void finalizePlanner(PlannerFixture plannerFixture) |
| { |
| } |
| } |
| |
| /** |
| * Builder for the framework. The component supplier and injector are |
| * required; all other items are optional. |
| */ |
| public static class Builder |
| { |
| private final QueryComponentSupplier componentSupplier; |
| private int minTopNThreshold = TopNQueryConfig.DEFAULT_MIN_TOPN_THRESHOLD; |
| private int mergeBufferCount; |
| private CatalogResolver catalogResolver = CatalogResolver.NULL_RESOLVER; |
| private List<Module> overrideModules = new ArrayList<>(); |
| |
| public Builder(QueryComponentSupplier componentSupplier) |
| { |
| this.componentSupplier = componentSupplier; |
| } |
| |
| public Builder minTopNThreshold(int minTopNThreshold) |
| { |
| this.minTopNThreshold = minTopNThreshold; |
| return this; |
| } |
| |
| public Builder mergeBufferCount(int mergeBufferCount) |
| { |
| this.mergeBufferCount = mergeBufferCount; |
| return this; |
| } |
| |
| public Builder catalogResolver(CatalogResolver catalogResolver) |
| { |
| this.catalogResolver = catalogResolver; |
| return this; |
| } |
| |
| public Builder withOverrideModule(Module m) |
| { |
| this.overrideModules.add(m); |
| return this; |
| } |
| |
| public SqlTestFramework build() |
| { |
| return new SqlTestFramework(this); |
| } |
| } |
| |
| /** |
| * Builds the statement factory, which also builds all the infrastructure |
| * behind the factory by calling methods on this test class. As a result, each |
| * factory is specific to one test and one planner config. This method can be |
| * overridden to control the objects passed to the factory. |
| */ |
| public static class PlannerFixture |
| { |
| private final ViewManager viewManager; |
| private final PlannerFactory plannerFactory; |
| private final SqlStatementFactory statementFactory; |
| |
| public PlannerFixture( |
| final SqlTestFramework framework, |
| final PlannerComponentSupplier componentSupplier, |
| final PlannerConfig plannerConfig, |
| final AuthConfig authConfig |
| ) |
| { |
| this.viewManager = componentSupplier.createViewManager(); |
| final DruidSchemaCatalog rootSchema = QueryFrameworkUtils.createMockRootSchema( |
| framework.injector, |
| framework.conglomerate(), |
| framework.walker(), |
| plannerConfig, |
| viewManager, |
| componentSupplier.createSchemaManager(), |
| framework.authorizerMapper, |
| framework.builder.catalogResolver |
| ); |
| |
| this.plannerFactory = new PlannerFactory( |
| rootSchema, |
| framework.operatorTable(), |
| framework.macroTable(), |
| plannerConfig, |
| framework.authorizerMapper, |
| framework.queryJsonMapper(), |
| CalciteTests.DRUID_SCHEMA_NAME, |
| new CalciteRulesManager(componentSupplier.extensionCalciteRules()), |
| framework.injector.getInstance(JoinableFactoryWrapper.class), |
| framework.builder.catalogResolver, |
| authConfig != null ? authConfig : new AuthConfig() |
| ); |
| componentSupplier.finalizePlanner(this); |
| this.statementFactory = QueryFrameworkUtils.createSqlStatementFactory( |
| framework.engine, |
| plannerFactory, |
| authConfig |
| ); |
| componentSupplier.populateViews(viewManager, plannerFactory); |
| } |
| |
| public ViewManager viewManager() |
| { |
| return viewManager; |
| } |
| |
| public PlannerFactory plannerFactory() |
| { |
| return plannerFactory; |
| } |
| |
| public SqlStatementFactory statementFactory() |
| { |
| return statementFactory; |
| } |
| } |
| |
| /** |
| * Guice module to create the various query framework items. By creating items within |
| * a module, later items can depend on those created earlier by grabbing them from the |
| * injector. This avoids the race condition that otherwise occurs if we try to build |
| * some of the items directly code, while others depend on the injector. |
| * <p> |
| * To allow customization, the instances are created via provider methods that pull |
| * dependencies from Guice, then call the component provider to create the instance. |
| * Tests customize the instances by overriding the instance creation methods. |
| * <p> |
| * This is an intermediate solution: the ultimate solution is to create things |
| * in Guice itself. |
| */ |
| private class TestSetupModule implements DruidModule |
| { |
| private final Builder builder; |
| |
| public TestSetupModule(Builder builder) |
| { |
| this.builder = builder; |
| } |
| |
| @Override |
| public void configure(Binder binder) |
| { |
| binder.bind(DruidOperatorTable.class).in(LazySingleton.class); |
| binder.bind(DataSegment.PruneSpecsHolder.class).toInstance(DataSegment.PruneSpecsHolder.DEFAULT); |
| binder.bind(DefaultColumnFormatConfig.class).toInstance(new DefaultColumnFormatConfig(null)); |
| } |
| |
| @Provides |
| @LazySingleton |
| public QueryRunnerFactoryConglomerate conglomerate() |
| { |
| return componentSupplier.createCongolmerate(builder, resourceCloser); |
| } |
| |
| @Provides |
| @LazySingleton |
| public JoinableFactoryWrapper joinableFactoryWrapper(final Injector injector) |
| { |
| return builder.componentSupplier.createJoinableFactoryWrapper( |
| injector.getInstance(LookupExtractorFactoryContainerProvider.class) |
| ); |
| } |
| |
| @Provides |
| @LazySingleton |
| public SpecificSegmentsQuerySegmentWalker segmentsQuerySegmentWalker(final Injector injector) |
| { |
| SpecificSegmentsQuerySegmentWalker walker = componentSupplier.createQuerySegmentWalker( |
| injector.getInstance(QueryRunnerFactoryConglomerate.class), |
| injector.getInstance(JoinableFactoryWrapper.class), |
| injector |
| ); |
| resourceCloser.register(walker); |
| return walker; |
| } |
| |
| @Provides |
| @LazySingleton |
| public QueryLifecycleFactory queryLifecycleFactory(final Injector injector) |
| { |
| return QueryFrameworkUtils.createMockQueryLifecycleFactory( |
| injector.getInstance(SpecificSegmentsQuerySegmentWalker.class), |
| injector.getInstance(QueryRunnerFactoryConglomerate.class) |
| ); |
| } |
| } |
| |
| public static final DruidViewMacroFactory DRUID_VIEW_MACRO_FACTORY = new TestDruidViewMacroFactory(); |
| |
| private final Builder builder; |
| private final QueryComponentSupplier componentSupplier; |
| private final Closer resourceCloser = Closer.create(); |
| private final Injector injector; |
| private final AuthorizerMapper authorizerMapper = CalciteTests.TEST_AUTHORIZER_MAPPER; |
| private final SqlEngine engine; |
| |
| private SqlTestFramework(Builder builder) |
| { |
| this.builder = builder; |
| this.componentSupplier = builder.componentSupplier; |
| Properties properties = new Properties(); |
| this.componentSupplier.gatherProperties(properties); |
| Injector startupInjector = new StartupInjectorBuilder() |
| .withProperties(properties) |
| .build(); |
| CoreInjectorBuilder injectorBuilder = (CoreInjectorBuilder) new CoreInjectorBuilder(startupInjector) |
| // Ignore load scopes. This is a unit test, not a Druid node. If a |
| // test pulls in a module, then pull in that module, even though we are |
| // not the Druid node to which the module is scoped. |
| .ignoreLoadScopes() |
| .addModule(new LookylooModule()) |
| .addModule(new SegmentWranglerModule()) |
| .addModule(new SqlAggregationModule()) |
| .addModule(new ExpressionModule()) |
| .addModule(new TestSetupModule(builder)); |
| |
| builder.componentSupplier.configureGuice(injectorBuilder); |
| |
| ServiceInjectorBuilder serviceInjector = new ServiceInjectorBuilder(injectorBuilder); |
| serviceInjector.addAll(builder.overrideModules); |
| |
| this.injector = serviceInjector.build(); |
| this.engine = builder.componentSupplier.createEngine(queryLifecycleFactory(), queryJsonMapper(), injector); |
| componentSupplier.configureJsonMapper(queryJsonMapper()); |
| componentSupplier.finalizeTestFramework(this); |
| } |
| |
| public Injector injector() |
| { |
| return injector; |
| } |
| |
| public SqlEngine engine() |
| { |
| return engine; |
| } |
| |
| public ObjectMapper queryJsonMapper() |
| { |
| return injector.getInstance(ObjectMapper.class); |
| } |
| |
| public QueryLifecycleFactory queryLifecycleFactory() |
| { |
| return injector.getInstance(QueryLifecycleFactory.class); |
| } |
| |
| public QueryLifecycle queryLifecycle() |
| { |
| return queryLifecycleFactory().factorize(); |
| } |
| |
| public ExprMacroTable macroTable() |
| { |
| return injector.getInstance(ExprMacroTable.class); |
| } |
| |
| public DruidOperatorTable operatorTable() |
| { |
| return injector.getInstance(DruidOperatorTable.class); |
| } |
| |
| public SpecificSegmentsQuerySegmentWalker walker() |
| { |
| return injector.getInstance(SpecificSegmentsQuerySegmentWalker.class); |
| } |
| |
| public QueryRunnerFactoryConglomerate conglomerate() |
| { |
| return injector.getInstance(QueryRunnerFactoryConglomerate.class); |
| } |
| |
| /** |
| * Creates an object (a "fixture") to hold the planner factory, view manager |
| * and related items. Most tests need just the statement factory. View-related |
| * tests also use the view manager. The fixture builds the infrastructure |
| * behind the factory by calling methods on the {@link QueryComponentSupplier} |
| * interface. That Calcite tests that interface, so the components can be customized |
| * by overriding methods in a particular tests. As a result, each |
| * planner fixture is specific to one test and one planner config. |
| */ |
| public PlannerFixture plannerFixture( |
| PlannerConfig plannerConfig, |
| AuthConfig authConfig |
| ) |
| { |
| PlannerComponentSupplier plannerComponentSupplier = componentSupplier.getPlannerComponentSupplier(); |
| return new PlannerFixture(this, plannerComponentSupplier, plannerConfig, authConfig); |
| } |
| |
| public void close() |
| { |
| try { |
| resourceCloser.close(); |
| componentSupplier.close(); |
| } |
| catch (IOException e) { |
| throw new RE(e); |
| } |
| } |
| } |