Turn config to valid yaml
- Moved all config settings with values in non leaf-nodes to leaf-nodes - Time units (Now .Time and .Unit) - Feature toggles (Now .Enabled) - Wrote tests to ensure non-leaf node values are not used Affects issues: - Fixed #1363
This commit is contained in:
parent
ea57d0dea1
commit
2b478e58c0
|
@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -239,7 +240,9 @@ public class ConfigNode {
|
|||
}
|
||||
|
||||
public <T> void set(T value) {
|
||||
if (value instanceof ConfigNode) {
|
||||
if (value == null) {
|
||||
this.value = null;
|
||||
} else if (value instanceof ConfigNode) {
|
||||
copyAll((ConfigNode) value);
|
||||
} else {
|
||||
ConfigValueParser<T> parser = ConfigValueParser.getParserFor(value.getClass());
|
||||
|
@ -277,7 +280,7 @@ public class ConfigNode {
|
|||
|
||||
public Double getDouble() {
|
||||
return value == null ? null
|
||||
: new ConfigValueParser.DoubleParser().compose(value);
|
||||
: new ConfigValueParser.DoubleParser().compose(value);
|
||||
}
|
||||
|
||||
public boolean getBoolean() {
|
||||
|
@ -318,6 +321,19 @@ public class ConfigNode {
|
|||
return configPaths;
|
||||
}
|
||||
|
||||
public <T> List<T> dfs(BiConsumer<ConfigNode, List<T>> accessVisitor) {
|
||||
ArrayDeque<ConfigNode> dfs = new ArrayDeque<>();
|
||||
dfs.push(this);
|
||||
|
||||
List<T> result = new ArrayList<>();
|
||||
while (!dfs.isEmpty()) {
|
||||
ConfigNode next = dfs.pop();
|
||||
accessVisitor.accept(next, result);
|
||||
dfs.addAll(next.getChildren());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Integer getInteger(String path) {
|
||||
return getNode(path).map(ConfigNode::getInteger).orElse(null);
|
||||
}
|
||||
|
@ -376,6 +392,11 @@ public class ConfigNode {
|
|||
}
|
||||
}
|
||||
|
||||
public void copyValue(ConfigNode from) {
|
||||
comment = from.comment;
|
||||
value = from.value;
|
||||
}
|
||||
|
||||
protected int getNodeDepth() {
|
||||
return parent != null ? parent.getNodeDepth() + 1 : -1; // Root node is -1
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package com.djrapitops.plan.settings.config.changes;
|
|||
import com.djrapitops.plan.settings.config.Config;
|
||||
import com.djrapitops.plan.settings.config.ConfigNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -88,6 +89,44 @@ public interface ConfigChange {
|
|||
}
|
||||
}
|
||||
|
||||
class MovedValue implements ConfigChange {
|
||||
|
||||
final String oldPath;
|
||||
final String newPath;
|
||||
|
||||
public MovedValue(String oldPath, String newPath) {
|
||||
this.oldPath = oldPath;
|
||||
this.newPath = newPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBeenApplied(Config config) {
|
||||
return config.getNode(oldPath)
|
||||
.map(ConfigNode::getString)
|
||||
.isEmpty()
|
||||
&& config.getNode(newPath).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Config config) {
|
||||
Optional<ConfigNode> oldNode = config.getNode(oldPath);
|
||||
if (oldNode.isPresent()) {
|
||||
ConfigNode node = oldNode.get();
|
||||
config.getNode(newPath)
|
||||
.orElseGet(() -> config.addNode(newPath))
|
||||
.copyValue(node);
|
||||
// Set value to null
|
||||
node.set(null);
|
||||
node.setComment(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAppliedMessage() {
|
||||
return "Moved " + oldPath + " to " + newPath;
|
||||
}
|
||||
}
|
||||
|
||||
class Copied extends Removed {
|
||||
|
||||
final String newPath;
|
||||
|
|
|
@ -149,7 +149,29 @@ public class ConfigUpdater {
|
|||
new ConfigChange.Removed("Database.H2.Password"),
|
||||
new ConfigChange.Removed("Database.H2"),
|
||||
|
||||
new ConfigChange.MoveLevelDown("World_aliases", "World_aliases.List")
|
||||
new ConfigChange.MoveLevelDown("World_aliases", "World_aliases.List"),
|
||||
|
||||
new ConfigChange.MovedValue("Webserver.Alternative_IP", "Webserver.Alternative_IP.Enabled"),
|
||||
new ConfigChange.MovedValue("Webserver.Security.IP_whitelist", "Webserver.Security.IP_whitelist.Enabled"),
|
||||
new ConfigChange.Moved("Formatting.Dates.Show_recent_day_names.DatePattern", "Formatting.Dates.Show_recent_day_names_date_pattern"),
|
||||
new ConfigChange.MovedValue("Export.Server_refresh_period", "Export.Server_refresh_period.Time"),
|
||||
new ConfigChange.MovedValue("Webserver.Security.Cookies_expire_after", "Webserver.Security.Cookies_expire_after.Time"),
|
||||
new ConfigChange.MovedValue("Webserver.Cache.Reduced_refresh_barrier", "Webserver.Cache.Reduced_refresh_barrier.Time"),
|
||||
new ConfigChange.MovedValue("Webserver.Cache.Invalidate_disk_cache_after", "Webserver.Cache.Invalidate_disk_cache_after.Time"),
|
||||
new ConfigChange.MovedValue("Webserver.Cache.Invalidate_memory_cache_after", "Webserver.Cache.Invalidate_memory_cache_after.Time"),
|
||||
new ConfigChange.MovedValue("Webserver.Cache.Invalidate_query_results_on_disk_after", "Webserver.Cache.Invalidate_query_results_on_disk_after.Time"),
|
||||
new ConfigChange.MovedValue("Time.Thresholds.Remove_disabled_extension_data_after", "Time.Thresholds.Remove_disabled_extension_data_after.Time"),
|
||||
new ConfigChange.MovedValue("Time.Thresholds.Remove_time_series_data_after", "Time.Thresholds.Remove_time_series_data_after.Time"),
|
||||
new ConfigChange.MovedValue("Time.Thresholds.Remove_ping_data_after", "Time.Thresholds.Remove_ping_data_after.Time"),
|
||||
new ConfigChange.MovedValue("Time.Thresholds.AFK_threshold", "Time.Thresholds.AFK_threshold.Time"),
|
||||
new ConfigChange.MovedValue("Time.Thresholds.Remove_inactive_player_data_after", "Time.Thresholds.Remove_inactive_player_data_after.Time"),
|
||||
new ConfigChange.MovedValue("Time.Periodic_tasks.Extension_data_refresh_every", "Time.Periodic_tasks.Extension_data_refresh_every.Time"),
|
||||
new ConfigChange.MovedValue("Time.Periodic_tasks.Check_DB_for_server_config_files_every", "Time.Periodic_tasks.Check_DB_for_server_config_files_every.Time"),
|
||||
new ConfigChange.MovedValue("Time.Periodic_tasks.Clean_Database_every", "Time.Periodic_tasks.Clean_Database_every.Time"),
|
||||
new ConfigChange.MovedValue("Time.Delays.Ping_server_enable_delay", "Time.Delays.Ping_server_enable_delay.Time"),
|
||||
new ConfigChange.MovedValue("Time.Delays.Ping_player_join_delay", "Time.Delays.Ping_player_join_delay.Time"),
|
||||
new ConfigChange.MovedValue("Time.Delays.Wait_for_DB_Transactions_on_disable", "Time.Delays.Wait_for_DB_Transactions_on_disable.Time"),
|
||||
new ConfigChange.MovedValue("Time.Thresholds.Activity_index.Playtime_threshold", "Time.Thresholds.Activity_index.Playtime_threshold.Time"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class FormatSettings {
|
|||
|
||||
public static final Setting<String> DECIMALS = new StringSetting("Formatting.Decimal_points");
|
||||
public static final Setting<Boolean> DATE_RECENT_DAYS = new BooleanSetting("Formatting.Dates.Show_recent_day_names");
|
||||
public static final Setting<String> DATE_RECENT_DAYS_PATTERN = new StringSetting("Formatting.Dates.Show_recent_day_names.DatePattern");
|
||||
public static final Setting<String> DATE_RECENT_DAYS_PATTERN = new StringSetting("Formatting.Dates.Show_recent_day_names_date_pattern");
|
||||
public static final Setting<String> DATE_FULL = new StringSetting("Formatting.Dates.Full");
|
||||
public static final Setting<String> DATE_NO_SECONDS = new StringSetting("Formatting.Dates.NoSeconds");
|
||||
public static final Setting<String> DATE_CLOCK = new StringSetting("Formatting.Dates.JustClock");
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
|
|||
public class WebserverSettings {
|
||||
|
||||
public static final Setting<Integer> PORT = new IntegerSetting("Webserver.Port");
|
||||
public static final Setting<Boolean> SHOW_ALTERNATIVE_IP = new BooleanSetting("Webserver.Alternative_IP");
|
||||
public static final Setting<Boolean> SHOW_ALTERNATIVE_IP = new BooleanSetting("Webserver.Alternative_IP.Enabled");
|
||||
public static final Setting<String> ALTERNATIVE_IP = new StringSetting("Webserver.Alternative_IP.Address");
|
||||
public static final Setting<String> INTERNAL_IP = new StringSetting("Webserver.Internal_IP");
|
||||
public static final Setting<String> CORS_ALLOW_ORIGIN = new StringSetting("Webserver.Security.CORS.Allow_origin");
|
||||
|
@ -38,7 +38,7 @@ public class WebserverSettings {
|
|||
public static final Setting<String> CERTIFICATE_STOREPASS = new StringSetting("Webserver.Security.SSL_certificate.Store_pass");
|
||||
public static final Setting<String> CERTIFICATE_ALIAS = new StringSetting("Webserver.Security.SSL_certificate.Alias");
|
||||
public static final Setting<Boolean> IP_USE_X_FORWARDED_FOR = new BooleanSetting("Webserver.Security.Use_X-Forwarded-For_Header");
|
||||
public static final Setting<Boolean> IP_WHITELIST = new BooleanSetting("Webserver.Security.IP_whitelist");
|
||||
public static final Setting<Boolean> IP_WHITELIST = new BooleanSetting("Webserver.Security.IP_whitelist.Enabled");
|
||||
public static final Setting<List<String>> WHITELIST = new StringListSetting("Webserver.Security.IP_whitelist.Whitelist");
|
||||
public static final Setting<Boolean> DISABLED = new BooleanSetting("Webserver.Disable_Webserver");
|
||||
public static final Setting<Boolean> DISABLED_AUTHENTICATION = new BooleanSetting("Webserver.Security.Disable_authentication");
|
||||
|
|
|
@ -48,7 +48,7 @@ public class TimeSetting extends Setting<Long> {
|
|||
|
||||
@Override
|
||||
public Long getValueFrom(ConfigNode node) {
|
||||
Long duration = node.getLong(path);
|
||||
Long duration = node.getLong(path + ".Time");
|
||||
if (duration == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -39,20 +39,25 @@ Database:
|
|||
# -----------------------------------------------------
|
||||
Webserver:
|
||||
Port: 8804
|
||||
Alternative_IP: false
|
||||
Alternative_IP:
|
||||
Enabled: false
|
||||
# %port% is replaced automatically with Webserver.Port
|
||||
Address: your.domain.here:%port%
|
||||
# InternalIP usually does not need to be changed, only change it if you know what you're doing!
|
||||
# 0.0.0.0 allocates Internal (local) IP automatically for the WebServer.
|
||||
Internal_IP: 0.0.0.0
|
||||
Cache:
|
||||
Reduced_refresh_barrier: 15
|
||||
Reduced_refresh_barrier:
|
||||
Time: 15
|
||||
Unit: SECONDS
|
||||
Invalidate_query_results_on_disk_after: 7
|
||||
Invalidate_query_results_on_disk_after:
|
||||
Time: 7
|
||||
Unit: DAYS
|
||||
Invalidate_disk_cache_after: 2
|
||||
Invalidate_disk_cache_after:
|
||||
Time: 2
|
||||
Unit: DAYS
|
||||
Invalidate_memory_cache_after: 5
|
||||
Invalidate_memory_cache_after:
|
||||
Time: 5
|
||||
Unit: MINUTES
|
||||
Security:
|
||||
SSL_certificate:
|
||||
|
@ -72,12 +77,14 @@ Webserver:
|
|||
Access_log:
|
||||
Print_to_console: false
|
||||
Remove_logs_after_days: 30
|
||||
IP_whitelist: false
|
||||
IP_whitelist:
|
||||
Enabled: false
|
||||
Whitelist:
|
||||
- "192.168.0.0"
|
||||
- "0:0:0:0:0:0:0:1"
|
||||
# Does not affect existing cookies
|
||||
Cookies_expire_after: 2
|
||||
Cookies_expire_after:
|
||||
Time: 2
|
||||
Unit: HOURS
|
||||
Disable_Webserver: false
|
||||
External_Webserver_address: "https://www.example.address"
|
||||
|
@ -94,37 +101,49 @@ Data_gathering:
|
|||
# -----------------------------------------------------
|
||||
Time:
|
||||
Delays:
|
||||
Ping_server_enable_delay: 300
|
||||
Ping_server_enable_delay:
|
||||
Time: 300
|
||||
Unit: SECONDS
|
||||
Ping_player_join_delay: 30
|
||||
Ping_player_join_delay:
|
||||
Time: 30
|
||||
Unit: SECONDS
|
||||
Wait_for_DB_Transactions_on_disable: 20
|
||||
Wait_for_DB_Transactions_on_disable:
|
||||
Time: 20
|
||||
Unit: SECONDS
|
||||
Thresholds:
|
||||
# How long player needs to be idle until Plan considers them AFK
|
||||
AFK_threshold: 3
|
||||
AFK_threshold:
|
||||
Time: 3
|
||||
Unit: MINUTES
|
||||
# Activity Index considers last 3 weeks and uses these thresholds in the calculation
|
||||
# The index is a number from 0 to 5.
|
||||
# These numbers were calibrated with data of 250 players (Small sample size).
|
||||
Activity_index:
|
||||
Playtime_threshold: 30
|
||||
Playtime_threshold:
|
||||
Time: 30
|
||||
Unit: MINUTES
|
||||
Remove_inactive_player_data_after: 180
|
||||
Remove_inactive_player_data_after:
|
||||
Time: 180
|
||||
Unit: DAYS
|
||||
# Includes players online, tps and performance time series
|
||||
Remove_time_series_data_after: 90
|
||||
Remove_time_series_data_after:
|
||||
Time: 90
|
||||
Unit: DAYS
|
||||
Remove_ping_data_after: 14
|
||||
Remove_ping_data_after:
|
||||
Time: 14
|
||||
Unit: DAYS
|
||||
Remove_disabled_extension_data_after: 2
|
||||
Remove_disabled_extension_data_after:
|
||||
Time: 2
|
||||
Unit: DAYS
|
||||
Periodic_tasks:
|
||||
Extension_data_refresh_every: 1
|
||||
Extension_data_refresh_every:
|
||||
Time: 1
|
||||
Unit: HOURS
|
||||
Check_DB_for_server_config_files_every: 1
|
||||
Check_DB_for_server_config_files_every:
|
||||
Time: 1
|
||||
Unit: MINUTES
|
||||
Clean_Database_every: 1
|
||||
Clean_Database_every:
|
||||
Time: 1
|
||||
Unit: HOURS
|
||||
# -----------------------------------------------------
|
||||
Display_options:
|
||||
|
@ -174,8 +193,8 @@ Formatting:
|
|||
Dates:
|
||||
# Show_recent_day_names replaces day number with Today, Yesterday, Wednesday etc.
|
||||
Show_recent_day_names: true
|
||||
# Non-regex pattern to replace
|
||||
DatePattern: 'MMM d YYYY'
|
||||
# Non-regex pattern to replace
|
||||
Show_recent_day_names_date_pattern: 'MMM d YYYY'
|
||||
Full: 'MMM d YYYY, HH:mm:ss'
|
||||
NoSeconds: 'MMM d YYYY, HH:mm'
|
||||
JustClock: 'HH:mm:ss'
|
||||
|
@ -212,7 +231,8 @@ Export:
|
|||
Export_player_on_login_and_logout: false
|
||||
# If there are multiple servers the period is divided evenly to avoid export of all servers at once
|
||||
# Also affects Players page export
|
||||
Server_refresh_period: 20
|
||||
Server_refresh_period:
|
||||
Time: 20
|
||||
Unit: MINUTES
|
||||
# -----------------------------------------------------
|
||||
# These settings affect Plugin data integration.
|
||||
|
|
|
@ -41,20 +41,25 @@ Database:
|
|||
# -----------------------------------------------------
|
||||
Webserver:
|
||||
Port: 8804
|
||||
Alternative_IP: false
|
||||
Alternative_IP:
|
||||
Enabled: false
|
||||
# %port% is replaced automatically with Webserver.Port
|
||||
Address: your.domain.here:%port%
|
||||
# InternalIP usually does not need to be changed, only change it if you know what you're doing!
|
||||
# 0.0.0.0 allocates Internal (local) IP automatically for the WebServer.
|
||||
Internal_IP: 0.0.0.0
|
||||
Cache:
|
||||
Reduced_refresh_barrier: 15
|
||||
Reduced_refresh_barrier:
|
||||
Time: 15
|
||||
Unit: SECONDS
|
||||
Invalidate_query_results_on_disk_after: 7
|
||||
Invalidate_query_results_on_disk_after:
|
||||
Time: 7
|
||||
Unit: DAYS
|
||||
Invalidate_disk_cache_after: 2
|
||||
Invalidate_disk_cache_after:
|
||||
Time: 2
|
||||
Unit: DAYS
|
||||
Invalidate_memory_cache_after: 5
|
||||
Invalidate_memory_cache_after:
|
||||
Time: 5
|
||||
Unit: MINUTES
|
||||
Security:
|
||||
SSL_certificate:
|
||||
|
@ -74,12 +79,14 @@ Webserver:
|
|||
Access_log:
|
||||
Print_to_console: false
|
||||
Remove_logs_after_days: 30
|
||||
IP_whitelist: false
|
||||
IP_whitelist:
|
||||
Enabled: false
|
||||
Whitelist:
|
||||
- "192.168.0.0"
|
||||
- "0:0:0:0:0:0:0:1"
|
||||
# Does not affect existing cookies
|
||||
Cookies_expire_after: 2
|
||||
Cookies_expire_after:
|
||||
Time: 2
|
||||
Unit: HOURS
|
||||
Disable_Webserver: false
|
||||
External_Webserver_address: https://www.example.address
|
||||
|
@ -99,37 +106,49 @@ Data_gathering:
|
|||
# -----------------------------------------------------
|
||||
Time:
|
||||
Delays:
|
||||
Ping_server_enable_delay: 300
|
||||
Ping_server_enable_delay:
|
||||
Time: 300
|
||||
Unit: SECONDS
|
||||
Ping_player_join_delay: 30
|
||||
Ping_player_join_delay:
|
||||
Time: 30
|
||||
Unit: SECONDS
|
||||
Wait_for_DB_Transactions_on_disable: 20
|
||||
Wait_for_DB_Transactions_on_disable:
|
||||
Time: 20
|
||||
Unit: SECONDS
|
||||
Thresholds:
|
||||
# How long player needs to be idle until Plan considers them AFK
|
||||
AFK_threshold: 3
|
||||
AFK_threshold:
|
||||
Time: 3
|
||||
Unit: MINUTES
|
||||
# Activity Index considers last 3 weeks and uses these thresholds in the calculation
|
||||
# The index is a number from 0 to 5.
|
||||
# These numbers were calibrated with data of 250 players (Small sample size).
|
||||
Activity_index:
|
||||
Playtime_threshold: 30
|
||||
Playtime_threshold:
|
||||
Time: 30
|
||||
Unit: MINUTES
|
||||
Remove_inactive_player_data_after: 180
|
||||
Remove_inactive_player_data_after:
|
||||
Time: 180
|
||||
Unit: DAYS
|
||||
# Includes players online, tps and performance time series
|
||||
Remove_time_series_data_after: 90
|
||||
Remove_time_series_data_after:
|
||||
Time: 90
|
||||
Unit: DAYS
|
||||
Remove_ping_data_after: 14
|
||||
Remove_ping_data_after:
|
||||
Time: 14
|
||||
Unit: DAYS
|
||||
Remove_disabled_extension_data_after: 2
|
||||
Remove_disabled_extension_data_after:
|
||||
Time: 2
|
||||
Unit: DAYS
|
||||
Periodic_tasks:
|
||||
Extension_data_refresh_every: 1
|
||||
Extension_data_refresh_every:
|
||||
Time: 1
|
||||
Unit: HOURS
|
||||
Check_DB_for_server_config_files_every: 1
|
||||
Check_DB_for_server_config_files_every:
|
||||
Time: 1
|
||||
Unit: MINUTES
|
||||
Clean_Database_every: 1
|
||||
Clean_Database_every:
|
||||
Time: 1
|
||||
Unit: HOURS
|
||||
# -----------------------------------------------------
|
||||
Display_options:
|
||||
|
@ -179,8 +198,8 @@ Formatting:
|
|||
Dates:
|
||||
# Show_recent_day_names replaces day number with Today, Yesterday, Wednesday etc.
|
||||
Show_recent_day_names: true
|
||||
# Non-regex pattern to replace
|
||||
DatePattern: 'MMM d YYYY'
|
||||
# Non-regex pattern to replace
|
||||
Show_recent_day_names_date_pattern: 'MMM d YYYY'
|
||||
Full: 'MMM d YYYY, HH:mm:ss'
|
||||
NoSeconds: 'MMM d YYYY, HH:mm'
|
||||
JustClock: HH:mm:ss
|
||||
|
@ -218,7 +237,8 @@ Export:
|
|||
Export_player_on_login_and_logout: false
|
||||
# If there are multiple servers the period is divided evenly to avoid export of all servers at once
|
||||
# Also affects Players page export
|
||||
Server_refresh_period: 20
|
||||
Server_refresh_period:
|
||||
Time: 20
|
||||
Unit: MINUTES
|
||||
# -----------------------------------------------------
|
||||
# These settings affect Plugin data integration.
|
||||
|
|
|
@ -29,6 +29,9 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test to check that configs contain all values required to run the plugin.
|
||||
|
@ -58,6 +61,32 @@ class ConfigSettingKeyTest {
|
|||
TestSettings.assertValidDefaultValuesForAllSettings(config, TestSettings.getProxySettings());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("config.yml key paths don't overlap")
|
||||
void serverConfigHasUniqueKeyPaths() throws IOException {
|
||||
PlanConfig config = createConfig("config.yml");
|
||||
checkConfigPathConflicts(config);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("bungeeconfig.yml key paths don't overlap")
|
||||
void proxyConfigHasUniqueKeyPaths() throws IOException {
|
||||
PlanConfig config = createConfig("bungeeconfig.yml");
|
||||
checkConfigPathConflicts(config);
|
||||
}
|
||||
|
||||
private void checkConfigPathConflicts(PlanConfig config) {
|
||||
List<Object> result = config.dfs((node, results) -> {
|
||||
String value = node.getString();
|
||||
boolean hasChildren = node.getChildren().isEmpty();
|
||||
boolean hasValue = value != null && !value.isEmpty();
|
||||
if (!hasChildren && hasValue) {
|
||||
results.add(node.getKey(true));
|
||||
}
|
||||
});
|
||||
assertTrue(result.isEmpty(), () -> "Following nodes have values and children: " + result);
|
||||
}
|
||||
|
||||
private PlanConfig createConfig(String copyDefaultSettingsFrom) throws IOException {
|
||||
File configFile = Files.createTempFile(temporaryFolder, "config", ".yml").toFile();
|
||||
TestResources.copyResourceIntoFile(configFile, "/assets/plan/" + copyDefaultSettingsFrom);
|
||||
|
|
|
@ -132,4 +132,17 @@ class ConfigChangeTest {
|
|||
assertFalse(config.contains("Test"), "Old node was not removed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void valueIsMoved() {
|
||||
config = prepareConfig("Test: \"value\"");
|
||||
config.addNode("Test.Child").set("anotherValue");
|
||||
|
||||
new ConfigChange.MovedValue("Test", "Test.SecondChild").apply(config);
|
||||
|
||||
assertNull(config.getString("Test"));
|
||||
assertNull(config.getString("Test.SecondChild.Child"));
|
||||
assertEquals("value", config.getString("Test.SecondChild"));
|
||||
assertEquals("anotherValue", config.getString("Test.Child"));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue