Skip to content

Improve retriever tests #1924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 4, 2025
2 changes: 1 addition & 1 deletion .github/junie-guidelines.md → .junie/guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ This document provides guidelines for the Junie AI assistant when working with t

## General Coding Guidelines
- Prefer **immutability** and use the `final` keyword for fields, parameters, and local variables when appropriate.
- Follow the **Effective Java** principles, particularly "Item 17 - Minimize Mutability" by using package-private constructors.
- Follow **Java 8 best practices**, including usage of `Optional`, `Streams`, and functional programming where applicable.
- Ensure **thread safety** by avoiding mutable shared state and using synchronized wrappers or concurrency utilities when necessary.
- Use **meaningful names** for classes, methods, and variables to improve code readability.
- Follow **SOLID principles** to enhance maintainability and scalability.
- Write meaningful **javadocs** for functions and classes.
- Follow the **Effective Java** principles, particularly "Item 17 - Minimize Mutability" by using package-private constructors.
- Use **builder pattern** for complex object construction.
- Implement clear **class hierarchies** with abstract base classes and specific implementations.
- Use **interfaces** extensively with well-defined implementations.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
========================================================================
SchemaCrawler
http://www.schemacrawler.com
Copyright (c) 2000-2025, Sualeh Fatehi <sualeh@hotmail.com>.
All rights reserved.
------------------------------------------------------------------------

SchemaCrawler is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

SchemaCrawler and the accompanying materials are made available under
the terms of the Eclipse Public License v1.0, GNU General Public License
v3 or GNU Lesser General Public License v3.

You may elect to redistribute this code under any of these licenses.

The Eclipse Public License is available at:
http://www.eclipse.org/legal/epl-v10.html

The GNU General Public License v3 and the GNU Lesser General Public
License v3 are available at:
http://www.gnu.org/licenses/

========================================================================
*/

package schemacrawler.crawl;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static schemacrawler.test.utility.DatabaseTestUtility.getCatalog;
import static schemacrawler.test.utility.DatabaseTestUtility.schemaRetrievalOptionsDefault;
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.jupiter.api.BeforeEach;
import schemacrawler.inclusionrule.RegularExpressionExclusionRule;
import schemacrawler.schemacrawler.InfoLevel;
import schemacrawler.schemacrawler.InformationSchemaKey;
import schemacrawler.schemacrawler.InformationSchemaViews;
import schemacrawler.schemacrawler.InformationSchemaViewsBuilder;
import schemacrawler.schemacrawler.LimitOptionsBuilder;
import schemacrawler.schemacrawler.LoadOptionsBuilder;
import schemacrawler.schemacrawler.MetadataRetrievalStrategy;
import schemacrawler.schemacrawler.SchemaCrawlerOptions;
import schemacrawler.schemacrawler.SchemaCrawlerOptionsBuilder;
import schemacrawler.schemacrawler.SchemaInfoLevelBuilder;
import schemacrawler.schemacrawler.SchemaInfoMetadataRetrievalStrategy;
import schemacrawler.schemacrawler.SchemaRetrievalOptions;
import schemacrawler.schemacrawler.SchemaRetrievalOptionsBuilder;
import schemacrawler.test.utility.WithTestDatabase;
import us.fatehi.utility.datasource.DatabaseConnectionSource;

/** An abstract base class for retriever tests to reduce code duplication. */
@WithTestDatabase
public abstract class AbstractRetrieverTest {

protected MutableCatalog catalog;

/**
* Loads a base catalog before each test.
*
* @param connection Database connection
*/
@BeforeEach
public void loadBaseCatalog(final Connection connection) {
final LimitOptionsBuilder limitOptionsBuilder =
LimitOptionsBuilder.builder()
.includeSchemas(new RegularExpressionExclusionRule(".*\\.FOR_LINT"));

// Create SchemaInfoLevelBuilder with base settings
final SchemaInfoLevelBuilder schemaInfoLevelBuilder =
SchemaInfoLevelBuilder.builder().withInfoLevel(getInfoLevel());

// Allow subclasses to customize the SchemaInfoLevelBuilder
customizeSchemaInfoLevel(schemaInfoLevelBuilder);

final LoadOptionsBuilder loadOptionsBuilder =
LoadOptionsBuilder.builder().withSchemaInfoLevel(schemaInfoLevelBuilder.toOptions());

final SchemaCrawlerOptions schemaCrawlerOptions =
SchemaCrawlerOptionsBuilder.newSchemaCrawlerOptions()
.withLimitOptions(limitOptionsBuilder.toOptions())
.withLoadOptions(loadOptionsBuilder.toOptions());

catalog =
(MutableCatalog)
getCatalog(connection, schemaRetrievalOptionsDefault, schemaCrawlerOptions);

assertThat(catalog, is(notNullValue()));
}

/**
* Customize the SchemaInfoLevelBuilder for specific retriever tests. Subclasses should override
* this method to disable specific object retrieval.
*
* @param schemaInfoLevelBuilder SchemaInfoLevelBuilder to customize
*/
protected void customizeSchemaInfoLevel(final SchemaInfoLevelBuilder schemaInfoLevelBuilder) {
// Default implementation does nothing
}

/**
* Creates a RetrieverConnection with custom information schema views.
*
* @param dataSource Database connection source
* @param informationSchemaKey Information schema key
* @param sql SQL query for the information schema view
* @param retrievalStrategy Metadata retrieval strategy
* @return RetrieverConnection
* @throws SQLException If a database access error occurs
*/
protected RetrieverConnection createRetrieverConnection(
final DatabaseConnectionSource dataSource,
final InformationSchemaKey informationSchemaKey,
final String sql,
final MetadataRetrievalStrategy retrievalStrategy)
throws SQLException {

final InformationSchemaViews informationSchemaViews =
InformationSchemaViewsBuilder.builder().withSql(informationSchemaKey, sql).toOptions();

final SchemaRetrievalOptionsBuilder schemaRetrievalOptionsBuilder =
SchemaRetrievalOptionsBuilder.builder();

if (retrievalStrategy != null) {
schemaRetrievalOptionsBuilder
.with(getRetrievalStrategyKey(), retrievalStrategy)
.withInformationSchemaViews(informationSchemaViews);
} else {
schemaRetrievalOptionsBuilder.withInformationSchemaViews(informationSchemaViews);
}

final SchemaRetrievalOptions schemaRetrievalOptions = schemaRetrievalOptionsBuilder.toOptions();

return new RetrieverConnection(dataSource, schemaRetrievalOptions);
}

/**
* Creates a RetrieverConnection with default schema retrieval options.
*
* @param dataSource Database connection source
* @return RetrieverConnection
* @throws SQLException If a database access error occurs
*/
protected RetrieverConnection createRetrieverConnection(final DatabaseConnectionSource dataSource)
throws SQLException {
return new RetrieverConnection(dataSource, schemaRetrievalOptionsDefault);
}

/**
* Creates default SchemaCrawlerOptions.
*
* @return SchemaCrawlerOptions
*/
protected SchemaCrawlerOptions createOptions() {
return SchemaCrawlerOptionsBuilder.newSchemaCrawlerOptions();
}

/**
* Gets the info level for the test. Override this method to change the info level.
*
* @return InfoLevel
*/
protected InfoLevel getInfoLevel() {
return InfoLevel.minimum;
}

/**
* Gets the retrieval strategy key for the test. Override this method to specify the retrieval
* strategy key.
*
* @return Retrieval strategy key
*/
protected abstract SchemaInfoMetadataRetrievalStrategy getRetrievalStrategyKey();
}
Loading
Loading