Skip to content

Commit

Permalink
Merge pull request #26184 from yrodiere/i26177-dev-services-drop-and-…
Browse files Browse the repository at this point in the history
…create-native-mode

Automatic drop-and-create of schema when using dev services in (native) integration tests
  • Loading branch information
gsmet committed Jun 21, 2022
2 parents 268fde2 + 1576718 commit e1e1129
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.quarkus.deployment.builditem;

import io.quarkus.builder.item.MultiBuildItem;

/**
* An additional configuration property to set when a dev service sets another, specific configuration property.
* <p>
* Quarkus will make sure the relevant settings are present in both JVM and native modes.
* <p>
* This is used to change the defaults of extension configuration when dev services are in use,
* for example to enable schema management in the Hibernate ORM extension.
*/
public final class DevServicesAdditionalConfigBuildItem extends MultiBuildItem {

private final String triggeringKey;
private final String key;
private final String value;
private final Runnable callbackWhenEnabled;

public DevServicesAdditionalConfigBuildItem(String triggeringKey,
String key, String value, Runnable callbackWhenEnabled) {
this.triggeringKey = triggeringKey;
this.key = key;
this.value = value;
this.callbackWhenEnabled = callbackWhenEnabled;
}

public String getTriggeringKey() {
return triggeringKey;
}

public String getKey() {
return key;
}

public String getValue() {
return value;
}

public Runnable getCallbackWhenEnabled() {
return callbackWhenEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Produce;
import io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem;
import io.quarkus.deployment.builditem.DevServicesAdditionalConfigBuildItem;
import io.quarkus.deployment.builditem.DevServicesConfigResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesNativeConfigResultBuildItem;
Expand All @@ -34,6 +35,7 @@ List<DevServicesConfigResultBuildItem> deprecated(List<DevServicesNativeConfigRe
DevServicesLauncherConfigResultBuildItem setup(BuildProducer<RunTimeConfigurationDefaultBuildItem> runtimeConfig,
List<DevServicesConfigResultBuildItem> devServicesConfigResultBuildItems,
List<DevServicesResultBuildItem> devServicesResultBuildItems,
List<DevServicesAdditionalConfigBuildItem> devServicesAdditionalConfigBuildItems,
CuratedApplicationShutdownBuildItem shutdownBuildItem) {
Map<String, String> newProperties = new HashMap<>(devServicesConfigResultBuildItems.stream().collect(
Collectors.toMap(DevServicesConfigResultBuildItem::getKey, DevServicesConfigResultBuildItem::getValue)));
Expand All @@ -60,10 +62,24 @@ public void run() {
}
}, true);
}
for (Map.Entry<String, String> entry : newProperties.entrySet()) {
oldConfig = newProperties;

Map<String, String> newPropertiesWithAdditionalConfig = new HashMap<>(newProperties);
// On contrary to dev services config, "additional" config build items are
// produced on each restart, so we don't want to remember them from one restart to the next.
for (DevServicesAdditionalConfigBuildItem item : devServicesAdditionalConfigBuildItems) {
if (newProperties.containsKey(item.getTriggeringKey())) {
var callback = item.getCallbackWhenEnabled();
if (callback != null) {
callback.run(); // This generally involves logging
}
newPropertiesWithAdditionalConfig.put(item.getKey(), item.getValue());
}
}

for (Map.Entry<String, String> entry : newPropertiesWithAdditionalConfig.entrySet()) {
runtimeConfig.produce(new RunTimeConfigurationDefaultBuildItem(entry.getKey(), entry.getValue()));
}
oldConfig = newProperties;
return new DevServicesLauncherConfigResultBuildItem(Collections.unmodifiableMap(newProperties));
return new DevServicesLauncherConfigResultBuildItem(Collections.unmodifiableMap(newPropertiesWithAdditionalConfig));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,14 @@
import io.quarkus.deployment.builditem.BytecodeRecorderConstantDefinitionBuildItem;
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesAdditionalConfigBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.builditem.LiveReloadBuildItem;
import io.quarkus.deployment.builditem.LogCategoryBuildItem;
import io.quarkus.deployment.builditem.NativeImageFeatureBuildItem;
import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem;
import io.quarkus.deployment.builditem.ServiceStartBuildItem;
import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
import io.quarkus.deployment.builditem.TransformedClassesBuildItem;
Expand Down Expand Up @@ -266,32 +265,33 @@ void warnOfSchemaProblems(HibernateOrmConfig config, HibernateOrmRecorder record
}

@BuildStep(onlyIfNot = IsNormal.class)
void devServicesAutoGenerateByDefault(DevServicesLauncherConfigResultBuildItem devServicesResult,
List<JdbcDataSourceSchemaReadyBuildItem> schemaReadyBuildItems,
void devServicesAutoGenerateByDefault(List<JdbcDataSourceSchemaReadyBuildItem> schemaReadyBuildItems,
List<PersistenceUnitDescriptorBuildItem> persistenceUnitDescriptorBuildItems,
HibernateOrmConfig config,
BuildProducer<RunTimeConfigurationDefaultBuildItem> runTimeConfigurationDefaultBuildItemBuildProducer) {
BuildProducer<DevServicesAdditionalConfigBuildItem> devServicesAdditionalConfigProducer) {
Set<String> managedSources = schemaReadyBuildItems.stream().map(JdbcDataSourceSchemaReadyBuildItem::getDatasourceNames)
.collect(HashSet::new, Collection::addAll, Collection::addAll);

for (Entry<String, HibernateOrmConfigPersistenceUnit> entry : config.getAllPersistenceUnitConfigsAsMap().entrySet()) {
String dsName;
Optional<String> ds = entry.getValue().datasource;
if (ds.isEmpty()) {
dsName = "quarkus.datasource.username";
String propertyKeyIndicatingDataSourceConfigured;
Optional<String> dataSourceName = entry.getValue().datasource;
if (dataSourceName.isEmpty()) {
propertyKeyIndicatingDataSourceConfigured = "quarkus.datasource.username";
} else {
dsName = "quarkus.datasource." + ds.get() + ".username";
propertyKeyIndicatingDataSourceConfigured = "quarkus.datasource." + dataSourceName.get() + ".username";
}

if (!ConfigUtils.isPropertyPresent(dsName)) {
if (devServicesResult.getConfig().containsKey(dsName)
&& !managedSources.contains(ds.orElse(DataSourceUtil.DEFAULT_DATASOURCE_NAME))) {
String propertyName = HibernateOrmRuntimeConfig.puPropertyKey(entry.getKey(), "database.generation");
if (!ConfigUtils.isPropertyPresent(propertyName)) {
LOG.info("Setting " + propertyName + "=drop-and-create to initialize Dev Services managed database");
runTimeConfigurationDefaultBuildItemBuildProducer
.produce(new RunTimeConfigurationDefaultBuildItem(propertyName, "drop-and-create"));
}
if (!managedSources.contains(dataSourceName.orElse(DataSourceUtil.DEFAULT_DATASOURCE_NAME))) {
String databaseGenerationPropertyKey = HibernateOrmRuntimeConfig.puPropertyKey(entry.getKey(),
"database.generation");
if (!ConfigUtils.isPropertyPresent(propertyKeyIndicatingDataSourceConfigured)
&& !ConfigUtils.isPropertyPresent(databaseGenerationPropertyKey)) {
String forcedValue = "drop-and-create";
devServicesAdditionalConfigProducer
.produce(new DevServicesAdditionalConfigBuildItem(propertyKeyIndicatingDataSourceConfigured,
databaseGenerationPropertyKey, forcedValue,
() -> LOG.infof("Setting %s=%s to initialize Dev Services managed database",
databaseGenerationPropertyKey, forcedValue)));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
{service.name}
</div>
<div class="card-body">
{#if service.containerInfo}
<ul class="list-group list-group-flush">
<li class="list-group-item">
<i class="fas fa-box-open" data-toggle="tooltip" data-placement="top" title="Container"></i> {service.containerInfo.getShortId()} {service.containerInfo.formatNames()}
Expand All @@ -26,6 +27,7 @@
</li>
</ul>
<hr/>
{/if}
<h5 class="card-title">Config</h5>
<code class="h-100">
{#for config in service.configs}
Expand Down

0 comments on commit e1e1129

Please sign in to comment.