All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.curs.celestaunit.CelestaUnitExtension Maven / Gradle / Ivy

package ru.curs.celestaunit;

import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;
import ru.curs.celesta.CallContext;
import ru.curs.celesta.Celesta;
import ru.curs.celesta.CelestaException;
import ru.curs.celesta.SystemCallContext;
import ru.curs.celesta.score.Grain;
import ru.curs.celesta.score.MaterializedView;
import ru.curs.celesta.score.Score;
import ru.curs.celesta.score.BasicTable;
import ru.curs.celesta.score.SequenceElement;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertSame;

/**
 * Extension class for JUnit5 tests.
 * 

* Creates Celesta using Score Path parameter and H2 embedded in-memory database. */ public final class CelestaUnitExtension implements BeforeAllCallback, AfterAllCallback, ParameterResolver, BeforeEachCallback, AfterEachCallback { static final String DEFAULT_SCORE = Stream.of("src/main/celestasql", "src/test/celestasql") .filter( s -> { File f = new File(s); return f.isDirectory() && f.canRead(); } ).collect(Collectors.joining(File.pathSeparator)); private final Parameters parameters; private final Namespace namespace; public CelestaUnitExtension() { this(new Parameters(builder())); } private CelestaUnitExtension(Parameters parameters) { this.parameters = parameters; namespace = Namespace.create(this); } /** * Returns builder for CelestaUnitExtension instance, allowing * to override default settings. * * @deprecated Use {@link CelestaTest} annotation parameters instead. */ @Deprecated public static Builder builder() { return new Builder(); } private Celesta celesta(ExtensionContext extensionContext) { return extensionContext.getStore(namespace).get(Celesta.class, Celesta.class); } Parameters getParameters() { return parameters; } @Override public void afterAll(ExtensionContext extensionContext) { Celesta celesta = celesta(extensionContext); try { try (Statement statement = celesta.getConnectionPool().get().createStatement()) { statement.execute("SHUTDOWN"); } celesta.close(); } catch (Exception e) { throw new CelestaException(e); } } @Override public void beforeAll(ExtensionContext extensionContext) { Properties params = new Properties(); params.setProperty("score.path", parameters.getScorePath(extensionContext)); params.setProperty("h2.in-memory", "true"); Celesta celesta = Celesta.createInstance(params); assertSame(celesta.getSetupProperties(), params); extensionContext.getStore(namespace).put(Celesta.class, celesta); try (Connection conn = celesta.getConnectionPool().get(); Statement stmt = conn.createStatement()) { stmt.execute("SET REFERENTIAL_INTEGRITY " + parameters.isReferentialIntegrity(extensionContext)); } catch (SQLException e) { throw new CelestaException(e); } } @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return parameterContext.getParameter().getType() == CallContext.class; } @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return extensionContext.getStore(namespace) .getOrComputeIfAbsent(extensionContext.getUniqueId(), k -> new SystemCallContext(celesta(extensionContext), extensionContext.getDisplayName()), CallContext.class); } @Override public void beforeEach(ExtensionContext extensionContext) { Celesta celesta = celesta(extensionContext); if (parameters.isTruncateTables(extensionContext)) { truncateTables(celesta, parameters.isReferentialIntegrity(extensionContext)); } if (parameters.isResetSequences(extensionContext)) { resetSequences(celesta); } } @Override public void afterEach(ExtensionContext extensionContext) { CallContext ctx = extensionContext .getStore(namespace) .remove(extensionContext.getUniqueId(), CallContext.class); if (ctx != null) { ctx.close(); } } private void truncateTables(Celesta celesta, boolean referentialIntegrity) { try (Connection conn = celesta.getConnectionPool().get(); Statement stmt = conn.createStatement()) { if (referentialIntegrity) { stmt.execute("SET REFERENTIAL_INTEGRITY FALSE"); } for (Map.Entry e : celesta.getScore().getGrains().entrySet()) { if (!Score.SYSTEM_SCHEMA_NAME.equals(e.getKey())) { Grain grain = e.getValue(); for (BasicTable table : grain.getTables().values()) { stmt.execute(String.format("truncate table %s.%s", grain.getQuotedName(), table.getQuotedName())); } for (MaterializedView view : grain.getMaterializedViews().values()) { stmt.execute(String.format("truncate table %s.%s", grain.getQuotedName(), view.getQuotedName())); } } } if (referentialIntegrity) { stmt.execute("SET REFERENTIAL_INTEGRITY TRUE"); } } catch (SQLException e) { throw new CelestaException(e); } } private void resetSequences(Celesta celesta) { try (Connection conn = celesta.getConnectionPool().get(); Statement stmt = conn.createStatement()) { for (Grain grain : celesta.getScore().getGrains().values()) { for (String seqName : grain.getElements(SequenceElement.class).keySet()) { stmt.execute(String.format("ALTER SEQUENCE \"%s\".\"%s\" RESTART WITH 1", grain.getName(), seqName)); conn.commit(); } } } catch (SQLException e) { throw new CelestaException(e); } } static final class Parameters { final String scorePath; final boolean referentialIntegrity; final boolean truncateTables; final boolean resetSequences; Parameters(Builder builder) { scorePath = builder.builderScorePath; referentialIntegrity = builder.builderReferentialIntegrity; truncateTables = builder.builderTruncateTables; resetSequences = builder.builderResetSequences; } String getScorePath(ExtensionContext extensionContext) { CelestaTest annotation = extensionContext.getRequiredTestClass().getAnnotation(CelestaTest.class); if (!(annotation == null || annotation.scorePath().isEmpty())) { return annotation.scorePath(); } else { return scorePath; } } boolean isReferentialIntegrity(ExtensionContext extensionContext) { CelestaTest annotation = extensionContext.getRequiredTestClass().getAnnotation(CelestaTest.class); if (annotation != null) { return annotation.referentialIntegrity(); } else { return referentialIntegrity; } } boolean isTruncateTables(ExtensionContext extensionContext) { CelestaTest annotation = extensionContext.getRequiredTestClass().getAnnotation(CelestaTest.class); if (annotation != null) { return annotation.truncateTables(); } else { return truncateTables; } } boolean isResetSequences(ExtensionContext extensionContext) { CelestaTest annotation = extensionContext.getRequiredTestClass().getAnnotation(CelestaTest.class); if (annotation != null) { return annotation.resetSequences(); } else { return resetSequences; } } } /** * Builder for CelestaUnitExtension, that allows to * override defaults. */ public static final class Builder { private String builderScorePath = DEFAULT_SCORE; private boolean builderReferentialIntegrity = true; private boolean builderTruncateTables = true; private boolean builderResetSequences = true; private Builder() { } /** * Sets score path. * * @param scorePath Score path (maybe relative to project root). */ public Builder withScorePath(String scorePath) { this.builderScorePath = scorePath; return this; } /** * Sets referential integrity. * * @param referentialIntegrity Set to false to disable. */ public Builder withReferentialIntegrity(boolean referentialIntegrity) { this.builderReferentialIntegrity = referentialIntegrity; return this; } /** * Sets tables truncation before each test (true by default). * * @param truncateTables Set to true to truncateTables each table before each test. */ public Builder withTruncateTables(boolean truncateTables) { this.builderTruncateTables = truncateTables; return this; } /** * Resets sequences before each test (true by default). * * @param resetSequences Set to true to reset sequences before each test */ public Builder withResetSequences(boolean resetSequences) { this.builderResetSequences = resetSequences; return this; } /** * Generates CelestaUnitExtension with given parameters. */ public CelestaUnitExtension build() { return new CelestaUnitExtension(new Parameters(this)); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy