Speedup build: introduced SharedSqlTestDatabase and DisposableSqlTestDatabase junit extensions (#1218)
* fixed PostgreSql migration scripts * introduces SharedSqlTestDatabaseExtension and DisposableSqlTestDatabaseExtension * Add cause msg to JUnitTestLoggerExtension Signed-off-by: Ahmed Sayed <ahmed.sayed@bosch.io> Signed-off-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io> Co-authored-by: Florian Ruschbaschan <florian.ruschbaschan@bosch.io>
This commit is contained in:
@@ -20,8 +20,10 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.repository.test.util.DisposableSqlTestDatabaseExtension;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
import io.qameta.allure.Feature;
|
||||
@@ -29,6 +31,7 @@ import io.qameta.allure.Story;
|
||||
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("System Management")
|
||||
@ExtendWith(DisposableSqlTestDatabaseExtension.class)
|
||||
public class SystemManagementTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,9 +19,11 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.test.util.DisposableSqlTestDatabaseExtension;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||
import org.eclipse.hawkbit.repository.test.util.WithUser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
@@ -36,6 +38,7 @@ import io.qameta.allure.Story;
|
||||
*/
|
||||
@Feature("Component Tests - Repository")
|
||||
@Story("Multi Tenancy")
|
||||
@ExtendWith(DisposableSqlTestDatabaseExtension.class)
|
||||
public class MultiTenancyEntityTest extends AbstractJpaIntegrationTest {
|
||||
|
||||
@Test
|
||||
|
||||
@@ -90,7 +90,7 @@ import org.springframework.test.context.TestExecutionListeners.MergeMode;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
@ActiveProfiles({ "test" })
|
||||
@ExtendWith({ JUnitTestLoggerExtension.class, WithSpringAuthorityRule.class })
|
||||
@ExtendWith({ JUnitTestLoggerExtension.class, WithSpringAuthorityRule.class , SharedSqlTestDatabaseExtension.class })
|
||||
@WithUser(principal = "bumlux", allSpPermissions = true, authorities = { CONTROLLER_ROLE, SYSTEM_ROLE })
|
||||
@SpringBootTest
|
||||
@ContextConfiguration(classes = { TestConfiguration.class, TestSupportBinderAutoConfiguration.class })
|
||||
@@ -102,9 +102,8 @@ import org.springframework.test.context.TestPropertySource;
|
||||
// Cleaning repository will fire "delete" events. We won't count them to the
|
||||
// test execution. So, the order execution between EventVerifier and Cleanup is
|
||||
// important!
|
||||
@TestExecutionListeners(listeners = { EventVerifier.class, CleanupTestExecutionListener.class,
|
||||
MySqlTestDatabase.class, MsSqlTestDatabase.class,
|
||||
PostgreSqlTestDatabase.class }, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
|
||||
@TestExecutionListeners(listeners = { EventVerifier.class, CleanupTestExecutionListener.class },
|
||||
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
|
||||
@TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true")
|
||||
public abstract class AbstractIntegrationTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractIntegrationTest.class);
|
||||
|
||||
@@ -8,48 +8,47 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import static java.sql.DriverManager.getConnection;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
/**
|
||||
* A {@link TestExecutionListener} for creating and dropping MySql schemas if
|
||||
* tests are setup with MySql.
|
||||
* A {@link TestExecutionListener} for creating and dropping SQL schemas if
|
||||
* tests are setup with an SQL schema.
|
||||
*/
|
||||
public abstract class AbstractSqlTestDatabase extends AbstractTestExecutionListener {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractSqlTestDatabase.class);
|
||||
protected String schemaName;
|
||||
protected String uri;
|
||||
protected String username;
|
||||
protected String password;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSqlTestDatabase.class);
|
||||
protected static final AntPathMatcher MATCHER = new AntPathMatcher();
|
||||
|
||||
@Override
|
||||
public void beforeTestClass(final TestContext testContext) throws Exception {
|
||||
if (isRunningWithSql()) {
|
||||
LOG.info("Setting up database for test class {}", testContext.getTestClass().getName());
|
||||
this.username = System.getProperty("spring.datasource.username");
|
||||
this.password = System.getProperty("spring.datasource.password");
|
||||
this.uri = System.getProperty("spring.datasource.url");
|
||||
createSchemaUri();
|
||||
createSchema();
|
||||
}
|
||||
protected final DatasourceContext context;
|
||||
|
||||
public AbstractSqlTestDatabase(final DatasourceContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestClass(final TestContext testContext) throws Exception {
|
||||
if (isRunningWithSql()) {
|
||||
dropSchema();
|
||||
protected abstract AbstractSqlTestDatabase createRandomSchema();
|
||||
|
||||
protected abstract void dropRandomSchema();
|
||||
|
||||
protected abstract String getRandomSchemaUri();
|
||||
|
||||
protected void executeStatement(final String uri, final String statement) {
|
||||
LOGGER.trace("\033[0;33mExecuting statement {} on uri {} \033[0m", statement, uri);
|
||||
|
||||
try (final Connection connection = getConnection(uri, context.getUsername(), context.getPassword());
|
||||
final PreparedStatement preparedStatement = connection.prepareStatement(statement)) {
|
||||
preparedStatement.execute();
|
||||
} catch (final SQLException e) {
|
||||
LOGGER.error("Execution of statement '{}' on uri {} failed!", statement, uri, e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void createSchemaUri();
|
||||
|
||||
protected abstract boolean isRunningWithSql();
|
||||
|
||||
protected abstract void createSchema();
|
||||
|
||||
protected abstract void dropSchema();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Holds all database related configuration
|
||||
*/
|
||||
public class DatasourceContext {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DatasourceContext.class);
|
||||
|
||||
public static final String SPRING_DATASOURCE_URL_KEY = "spring.datasource.url";
|
||||
public static final String SPRING_DATABASE_KEY = "spring.jpa.database";
|
||||
public static final String SPRING_DATABASE_USERNAME_KEY = "spring.datasource.username";
|
||||
public static final String SPRING_DATABASE_PASSWORD_KEY = "spring.datasource.password";
|
||||
public static final String DATABASE_PREFIX_KEY = "spring.database.random.prefix";
|
||||
private static final String RANDOM_DB_PREFIX = System.getProperty(DATABASE_PREFIX_KEY, "HAWKBIT_TEST_");
|
||||
|
||||
private final String database;
|
||||
private final String datasourceUrl;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final String randomSchemaName = RANDOM_DB_PREFIX + RandomStringUtils.randomAlphanumeric(10);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public DatasourceContext(final String database, final String datasourceUrl, final String username,
|
||||
final String password) {
|
||||
this.database = database;
|
||||
this.datasourceUrl = datasourceUrl;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public DatasourceContext() {
|
||||
database = System.getProperty(SPRING_DATABASE_KEY, System.getProperty(upperCaseVariant(SPRING_DATABASE_KEY)));
|
||||
datasourceUrl = System.getProperty(SPRING_DATASOURCE_URL_KEY,
|
||||
System.getProperty(upperCaseVariant(SPRING_DATASOURCE_URL_KEY)));
|
||||
username = System.getProperty(SPRING_DATABASE_USERNAME_KEY,
|
||||
System.getProperty(upperCaseVariant(SPRING_DATABASE_USERNAME_KEY)));
|
||||
password = System.getProperty(SPRING_DATABASE_PASSWORD_KEY,
|
||||
System.getProperty(upperCaseVariant(SPRING_DATABASE_PASSWORD_KEY)));
|
||||
}
|
||||
|
||||
private static String upperCaseVariant(final String key) {
|
||||
return key.toUpperCase().replace('.', '_');
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public String getDatasourceUrl() {
|
||||
return datasourceUrl;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getRandomSchemaName() {
|
||||
return randomSchemaName;
|
||||
}
|
||||
|
||||
public boolean isNotProperlyConfigured() {
|
||||
LOGGER.debug("Datasource environment variables: [database: {}, username: {}, password: {}, datasourceUrl: {}]",
|
||||
database, username, password, datasourceUrl);
|
||||
|
||||
return database == null || datasourceUrl == null || username == null || password == null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.test.util.DatasourceContext.SPRING_DATASOURCE_URL_KEY;
|
||||
|
||||
/**
|
||||
* Provides a convenient way to generate a test database that can be used, and disposed of after the test is executed.
|
||||
*/
|
||||
public class DisposableSqlTestDatabaseExtension extends SharedSqlTestDatabaseExtension implements AfterAllCallback {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SharedSqlTestDatabaseExtension.class);
|
||||
|
||||
private DatasourceContext datasourceContext = null;
|
||||
|
||||
@Override
|
||||
public void beforeAll(final ExtensionContext extensionContext) {
|
||||
super.beforeAll(extensionContext);
|
||||
final DatasourceContext sharedContext = CONTEXT.get();
|
||||
if (sharedContext == null || sharedContext.isNotProperlyConfigured()) {
|
||||
return;
|
||||
}
|
||||
datasourceContext = new DatasourceContext(sharedContext.getDatabase(), sharedContext.getDatasourceUrl(),
|
||||
sharedContext.getUsername(), sharedContext.getPassword());
|
||||
final AbstractSqlTestDatabase database = matchingDatabase(datasourceContext);
|
||||
final String randomSchemaUri = database.createRandomSchema().getRandomSchemaUri();
|
||||
LOGGER.info("\033[0;33mRandom Schema URI is {} \033[0m", randomSchemaUri);
|
||||
System.setProperty(SPRING_DATASOURCE_URL_KEY, randomSchemaUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll(final ExtensionContext extensionContext) {
|
||||
if (datasourceContext == null) {
|
||||
return;
|
||||
}
|
||||
matchingDatabase(datasourceContext).dropRandomSchema();
|
||||
System.setProperty(SPRING_DATASOURCE_URL_KEY, matchingDatabase(CONTEXT.get()).getRandomSchemaUri());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
|
||||
/**
|
||||
* An {@link Extension} for creating and dropping H2 schemas if
|
||||
* tests are set up with H2.
|
||||
*/
|
||||
public class H2TestDatabase extends AbstractSqlTestDatabase {
|
||||
|
||||
public H2TestDatabase(final DatasourceContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public H2TestDatabase createRandomSchema() {
|
||||
// do nothing, since H2 is in memory
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropRandomSchema() {
|
||||
// do nothing, since H2 is in memory
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRandomSchemaUri() {
|
||||
return "jdbc:h2:mem:" + context.getRandomSchemaName() +";MODE=MySQL;";
|
||||
}
|
||||
}
|
||||
@@ -19,17 +19,17 @@ public class JUnitTestLoggerExtension implements BeforeTestExecutionCallback, Te
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JUnitTestLoggerExtension.class);
|
||||
|
||||
@Override
|
||||
public void testSuccessful(ExtensionContext context) {
|
||||
public void testSuccessful(final ExtensionContext context) {
|
||||
LOG.info("Test {} succeeded.", context.getTestMethod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testFailed(ExtensionContext context, Throwable cause) {
|
||||
LOG.error("Test {} failed with {}.", context.getTestMethod());
|
||||
public void testFailed(final ExtensionContext context, final Throwable cause) {
|
||||
LOG.error("Test {} failed with {}.", context.getTestMethod(), cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTestExecution(ExtensionContext context) throws Exception {
|
||||
public void beforeTestExecution(final ExtensionContext context) {
|
||||
LOG.info("Starting Test {}...", context.getTestMethod());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,67 +8,45 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
|
||||
/**
|
||||
* A {@link TestExecutionListener} for creating and dropping MS SQL Server
|
||||
* schemas if tests are setup with MS SQL Server.
|
||||
* An {@link Extension} for creating and dropping MS SQL Server
|
||||
* schemas if tests are set up with MS SQL Server.
|
||||
*/
|
||||
public class MsSqlTestDatabase extends AbstractSqlTestDatabase {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MsSqlTestDatabase.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MsSqlTestDatabase.class);
|
||||
|
||||
@Override
|
||||
protected void createSchemaUri() {
|
||||
schemaName = "SP" + RandomStringUtils.randomAlphanumeric(10);
|
||||
this.uri = this.uri.substring(0, uri.indexOf(';'));
|
||||
|
||||
System.setProperty("spring.datasource.url", uri + ";database=" + schemaName);
|
||||
public MsSqlTestDatabase(final DatasourceContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunningWithSql() {
|
||||
return "SQL_SERVER".equals(System.getProperty("spring.jpa.database"));
|
||||
public MsSqlTestDatabase createRandomSchema() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
LOGGER.info("\033[0;33mCreating mssql schema {} \033[0m", context.getRandomSchemaName());
|
||||
|
||||
executeStatement(uri.split(";database=")[0], "CREATE DATABASE " + context.getRandomSchemaName() + ";");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createSchema() {
|
||||
try (Connection connection = DriverManager.getConnection(uri, username, password)) {
|
||||
try (PreparedStatement statement = connection.prepareStatement("CREATE DATABASE " + schemaName + ";")) {
|
||||
LOG.info("Creating schema {} on uri {}", schemaName, uri);
|
||||
statement.execute();
|
||||
LOG.info("Created schema {} on uri {}", schemaName, uri);
|
||||
}
|
||||
} catch (final SQLException e) {
|
||||
LOG.error("Schema creation failed!", e);
|
||||
}
|
||||
protected void dropRandomSchema() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
final String dbServerUri = uri.split(";database=")[0];
|
||||
LOGGER.info("\033[0;33mDropping mssql schema {} \033[0m", context.getRandomSchemaName());
|
||||
|
||||
// Needed to avoid the DROP is rejected with "database still in use"
|
||||
executeStatement(dbServerUri, "ALTER DATABASE " + context.getRandomSchemaName() + " SET SINGLE_USER WITH ROLLBACK IMMEDIATE;");
|
||||
executeStatement(dbServerUri, "DROP DATABASE " + context.getRandomSchemaName() + ";");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropSchema() {
|
||||
try (Connection connection = DriverManager.getConnection(uri, username, password)) {
|
||||
// Needed to avoid the DROP is rejected with "database still in use"
|
||||
try (PreparedStatement statement = connection
|
||||
.prepareStatement("ALTER DATABASE " + schemaName + " SET SINGLE_USER WITH ROLLBACK IMMEDIATE;")) {
|
||||
statement.execute();
|
||||
}
|
||||
|
||||
try (PreparedStatement statement = connection.prepareStatement("DROP DATABASE " + schemaName + ";")) {
|
||||
LOG.info("Dropping schema {} on uri {}", schemaName, uri);
|
||||
statement.execute();
|
||||
LOG.info("Dropped schema {} on uri {}", schemaName, uri);
|
||||
}
|
||||
} catch (final SQLException e) {
|
||||
LOG.error("Schema drop failed!", e);
|
||||
}
|
||||
protected String getRandomSchemaUri() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
return uri.substring(0, uri.indexOf(';')) + ";database=" + context.getRandomSchemaName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,61 +8,55 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
|
||||
/**
|
||||
* A {@link TestExecutionListener} for creating and dropping MySql schemas if
|
||||
* tests are setup with MySql.
|
||||
* An {@link Extension} for creating and dropping MySql schemas if
|
||||
* tests are set up with MySql.
|
||||
*/
|
||||
public class MySqlTestDatabase extends AbstractSqlTestDatabase {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MySqlTestDatabase.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MySqlTestDatabase.class);
|
||||
protected static final String MYSQL_URI_PATTERN = "jdbc:mysql://{host}:{port}/{db}*";
|
||||
|
||||
@Override
|
||||
protected void createSchemaUri() {
|
||||
schemaName = "SP" + RandomStringUtils.randomAlphanumeric(10);
|
||||
this.uri = this.uri.substring(0, uri.lastIndexOf('/') + 1);
|
||||
|
||||
System.setProperty("spring.datasource.url", uri + schemaName);
|
||||
public MySqlTestDatabase(final DatasourceContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunningWithSql() {
|
||||
return "MYSQL".equals(System.getProperty("spring.jpa.database"));
|
||||
public MySqlTestDatabase createRandomSchema() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
final String schemaName = getSchemaName(uri);
|
||||
LOGGER.info("\033[0;33mCreating mysql schema {} if not existing \033[0m", context.getRandomSchemaName());
|
||||
|
||||
executeStatement(uri.split("/" + schemaName)[0],
|
||||
"CREATE SCHEMA IF NOT EXISTS " + context.getRandomSchemaName() + ";");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createSchema() {
|
||||
try (Connection connection = DriverManager.getConnection(uri, username, password)) {
|
||||
try (PreparedStatement statement = connection.prepareStatement("CREATE SCHEMA " + schemaName + ";")) {
|
||||
LOG.info("Creating schema {} on uri {}", schemaName, uri);
|
||||
statement.execute();
|
||||
LOG.info("Created schema {} on uri {}", schemaName, uri);
|
||||
}
|
||||
} catch (final SQLException e) {
|
||||
LOG.error("Schema creation failed!", e);
|
||||
}
|
||||
|
||||
protected void dropRandomSchema() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
final String schemaName = getSchemaName(uri);
|
||||
LOGGER.info("\033[0;33mDropping mysql schema {} \033[0m", context.getRandomSchemaName());
|
||||
executeStatement(uri.split("/" + schemaName)[0], "DROP SCHEMA " + context.getRandomSchemaName() + ";");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropSchema() {
|
||||
try (Connection connection = DriverManager.getConnection(uri, username, password)) {
|
||||
try (PreparedStatement statement = connection.prepareStatement("DROP SCHEMA " + schemaName + ";")) {
|
||||
LOG.info("Dropping schema {} on uri {}", schemaName, uri);
|
||||
statement.execute();
|
||||
LOG.info("Dropped schema {} on uri {}", schemaName, uri);
|
||||
}
|
||||
} catch (final SQLException e) {
|
||||
LOG.error("Schema drop failed!", e);
|
||||
}
|
||||
protected String getRandomSchemaUri() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
final Map<String, String> databaseProperties = MATCHER.extractUriTemplateVariables(MYSQL_URI_PATTERN, uri);
|
||||
|
||||
return MYSQL_URI_PATTERN.replace("{host}", databaseProperties.get("host"))
|
||||
.replace("{port}", databaseProperties.get("port"))
|
||||
.replace("{db}*", context.getRandomSchemaName());
|
||||
}
|
||||
|
||||
private static String getSchemaName(final String datasourceUrl) {
|
||||
return MATCHER.extractUriTemplateVariables(MYSQL_URI_PATTERN, datasourceUrl).get("db");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,61 +8,57 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.extension.Extension;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
|
||||
/**
|
||||
* A {@link TestExecutionListener} for creating and dropping MySql schemas if
|
||||
* tests are setup with MySql.
|
||||
* An {@link Extension} for creating and dropping MySql schemas if
|
||||
* tests are set up with MySql.
|
||||
*/
|
||||
public class PostgreSqlTestDatabase extends AbstractSqlTestDatabase {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlTestDatabase.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PostgreSqlTestDatabase.class);
|
||||
private static final String POSTGRESQL_URI_PATTERN = "jdbc:postgresql://{host}:{port}/{db}*";
|
||||
|
||||
@Override
|
||||
protected void createSchemaUri() {
|
||||
schemaName = "sp" + RandomStringUtils.randomAlphanumeric(10).toLowerCase();
|
||||
this.uri = this.uri.substring(0, uri.indexOf('?'));
|
||||
|
||||
System.setProperty("spring.datasource.url", uri + "?currentSchema=" + schemaName);
|
||||
public PostgreSqlTestDatabase(final DatasourceContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRunningWithSql() {
|
||||
return "POSTGRESQL".equals(System.getProperty("spring.jpa.database"));
|
||||
protected PostgreSqlTestDatabase createRandomSchema() {
|
||||
LOGGER.info("\033[0;33mCreating postgreSql schema {} \033[0m", context.getRandomSchemaName());
|
||||
final String uri = getBaseUri() + "?currentSchema=" + getSchemaName();
|
||||
executeStatement(uri, "CREATE SCHEMA " + context.getRandomSchemaName() + ";");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createSchema() {
|
||||
try (Connection connection = DriverManager.getConnection(uri, username, password)) {
|
||||
try (PreparedStatement statement = connection.prepareStatement("CREATE schema " + schemaName + ";")) {
|
||||
LOG.info("Creating schema {} on uri {}", schemaName, uri);
|
||||
statement.execute();
|
||||
LOG.info("Created schema {} on uri {}", schemaName, uri);
|
||||
}
|
||||
} catch (final SQLException e) {
|
||||
LOG.error("Schema creation failed!", e);
|
||||
}
|
||||
|
||||
protected void dropRandomSchema() {
|
||||
LOGGER.info("\033[0;33mDropping postgreSql schema {}\033[0m", context.getRandomSchemaName());
|
||||
final String uri = getBaseUri() + "?currentSchema=" + getSchemaName();
|
||||
executeStatement(uri, "DROP SCHEMA " + context.getRandomSchemaName() + " CASCADE;");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropSchema() {
|
||||
try (Connection connection = DriverManager.getConnection(uri, username, password)) {
|
||||
try (PreparedStatement statement = connection.prepareStatement("DROP schema " + schemaName + " CASCADE;")) {
|
||||
LOG.info("Dropping schema {} on uri {}", schemaName, uri);
|
||||
statement.execute();
|
||||
LOG.info("Dropped schema {} on uri {}", schemaName, uri);
|
||||
}
|
||||
} catch (final SQLException e) {
|
||||
LOG.error("Schema drop failed!", e);
|
||||
}
|
||||
protected String getRandomSchemaUri() {
|
||||
return getBaseUri() + "?currentSchema=" + context.getRandomSchemaName();
|
||||
}
|
||||
|
||||
private String getBaseUri() {
|
||||
final String uri = context.getDatasourceUrl();
|
||||
final Map<String, String> databaseProperties = MATCHER.extractUriTemplateVariables(POSTGRESQL_URI_PATTERN, uri);
|
||||
|
||||
return POSTGRESQL_URI_PATTERN.replace("{host}", databaseProperties.get("host"))
|
||||
.replace("{port}", databaseProperties.get("port"))
|
||||
.replace("{db}*", getSchemaName());
|
||||
}
|
||||
|
||||
private String getSchemaName() {
|
||||
return MATCHER.extractUriTemplateVariables(POSTGRESQL_URI_PATTERN, context.getDatasourceUrl())
|
||||
.get("db")
|
||||
.split("\\?")[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.test.util;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.test.util.DatasourceContext.SPRING_DATASOURCE_URL_KEY;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Represents a test database configuration for a "shared" database instance across all tests annotated with this extension
|
||||
*/
|
||||
public class SharedSqlTestDatabaseExtension implements BeforeAllCallback {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SharedSqlTestDatabaseExtension.class);
|
||||
protected static final AtomicReference<DatasourceContext> CONTEXT = new AtomicReference<>();
|
||||
|
||||
@Override
|
||||
public void beforeAll(final ExtensionContext extensionContext) {
|
||||
final DatasourceContext testDatasourceContext = new DatasourceContext();
|
||||
|
||||
if (testDatasourceContext.isNotProperlyConfigured()) {
|
||||
LOGGER.info("\033[0;33mSchema generation skipped... No datasource environment variables found!\033[0m");
|
||||
return;
|
||||
}
|
||||
|
||||
// update CONTEXT only if the current value is null => initialize only
|
||||
if (!CONTEXT.compareAndSet(null, testDatasourceContext)) {
|
||||
final String randomSchemaUri = matchingDatabase(testDatasourceContext).getRandomSchemaUri();
|
||||
LOGGER.info("\033[0;33mReusing Random Schema at URI {} \033[0m", randomSchemaUri);
|
||||
return;
|
||||
}
|
||||
|
||||
final AbstractSqlTestDatabase database = matchingDatabase(testDatasourceContext);
|
||||
final String randomSchemaUri = database.createRandomSchema().getRandomSchemaUri();
|
||||
LOGGER.info("\033[0;33mRandom Schema URI is {} \033[0m", randomSchemaUri);
|
||||
System.setProperty(SPRING_DATASOURCE_URL_KEY, randomSchemaUri);
|
||||
|
||||
registerDropSchemaOnSystemShutdownHook(database, randomSchemaUri);
|
||||
}
|
||||
|
||||
private void registerDropSchemaOnSystemShutdownHook(final AbstractSqlTestDatabase database, final String schemaUri) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
LOGGER.warn("\033[0;33mDropping schema at url {} \033[0m", schemaUri);
|
||||
database.dropRandomSchema();
|
||||
}));
|
||||
}
|
||||
|
||||
protected AbstractSqlTestDatabase matchingDatabase(final DatasourceContext context) {
|
||||
AbstractSqlTestDatabase database;
|
||||
|
||||
switch (context.getDatabase()) {
|
||||
case "H2":
|
||||
database = new H2TestDatabase(context);
|
||||
break;
|
||||
case "SQL_SERVER":
|
||||
database = new MsSqlTestDatabase(context);
|
||||
break;
|
||||
case "MYSQL":
|
||||
database = new MySqlTestDatabase(context);
|
||||
break;
|
||||
case "POSTGRESQL":
|
||||
database = new PostgreSqlTestDatabase(context);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("No supported database found for type " + context.getDatabase());
|
||||
}
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,24 +8,19 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.app;
|
||||
|
||||
import org.eclipse.hawkbit.repository.test.util.MsSqlTestDatabase;
|
||||
import org.eclipse.hawkbit.repository.test.util.MySqlTestDatabase;
|
||||
import org.eclipse.hawkbit.repository.test.util.SharedSqlTestDatabaseExtension;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.TestExecutionListeners.MergeMode;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
@SpringBootTest(properties = { "hawkbit.dmf.rabbitmq.enabled=false" })
|
||||
@TestExecutionListeners(listeners = { MySqlTestDatabase.class,
|
||||
MsSqlTestDatabase.class }, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
|
||||
@DirtiesContext
|
||||
@ExtendWith(SharedSqlTestDatabaseExtension.class)
|
||||
public abstract class AbstractSecurityTest {
|
||||
|
||||
@Autowired
|
||||
@@ -40,4 +35,4 @@ public abstract class AbstractSecurityTest {
|
||||
mvc = builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.repository.test.util.MsSqlTestDatabase;
|
||||
import org.eclipse.hawkbit.repository.test.util.MySqlTestDatabase;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.test.context.support.WithUserDetails;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.TestExecutionListeners.MergeMode;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
import io.qameta.allure.Description;
|
||||
@@ -31,10 +28,7 @@ import io.qameta.allure.Story;
|
||||
@SpringBootTest(properties = { "hawkbit.dmf.rabbitmq.enabled=false", "hawkbit.server.security.cors.enabled=true",
|
||||
"hawkbit.server.security.cors.allowedOrigins=" + CorsTest.ALLOWED_ORIGIN_FIRST + ","
|
||||
+ CorsTest.ALLOWED_ORIGIN_SECOND,
|
||||
"hawkbit.server.security.cors.exposedHeaders=Access-Control-Allow-Origin" })
|
||||
@TestExecutionListeners(listeners = { MySqlTestDatabase.class,
|
||||
MsSqlTestDatabase.class }, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
|
||||
@Feature("Integration Test - Security")
|
||||
"hawkbit.server.security.cors.exposedHeaders=Access-Control-Allow-Origin" })@Feature("Integration Test - Security")
|
||||
@Story("CORS")
|
||||
public class CorsTest extends AbstractSecurityTest {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user