|
| 1 | +package dev.objz.commandbridge.config; |
| 2 | + |
| 3 | +import dev.objz.commandbridge.config.model.BackendsConfig; |
| 4 | +import dev.objz.commandbridge.logging.Log; |
| 5 | +import org.junit.jupiter.api.BeforeAll; |
| 6 | +import org.junit.jupiter.api.Test; |
| 7 | +import org.junit.jupiter.api.io.TempDir; |
| 8 | + |
| 9 | +import java.io.IOException; |
| 10 | +import java.nio.file.Files; |
| 11 | +import java.nio.file.Path; |
| 12 | + |
| 13 | +import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 14 | +import static org.junit.jupiter.api.Assertions.assertNull; |
| 15 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
| 16 | + |
| 17 | +class ConfigManagerTest { |
| 18 | + |
| 19 | + @BeforeAll |
| 20 | + static void installLog() { |
| 21 | + try { |
| 22 | + Log.install(java.util.logging.Logger.getLogger("config-test")); |
| 23 | + } catch (IllegalStateException ignored) { |
| 24 | + // already installed by another test class |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + @Test |
| 29 | + void loadCreatesDefaultWhenFileMissing(@TempDir Path tempDir) { |
| 30 | + var manager = new ConfigManager<>(tempDir, BackendsConfig.class); |
| 31 | + |
| 32 | + boolean result = manager.load(); |
| 33 | + |
| 34 | + assertTrue(result, "load() should return true for freshly-created defaults"); |
| 35 | + assertTrue(Files.exists(tempDir.resolve("config.yml")), "config.yml should be created"); |
| 36 | + assertNotNull(manager.current(), "current() should not be null after load"); |
| 37 | + } |
| 38 | + |
| 39 | + @Test |
| 40 | + void loadReturnsTrueWithValidYaml(@TempDir Path tempDir) throws IOException { |
| 41 | + Path configFile = tempDir.resolve("config.yml"); |
| 42 | + Files.writeString(configFile, validYaml("lobby-1")); |
| 43 | + |
| 44 | + var manager = new ConfigManager<>(tempDir, BackendsConfig.class); |
| 45 | + boolean result = manager.load(); |
| 46 | + |
| 47 | + assertTrue(result, "load() should return true for valid YAML"); |
| 48 | + assertNotNull(manager.current(), "current() should not be null"); |
| 49 | + assertTrue("lobby-1".equals(manager.current().clientId()), |
| 50 | + "clientId should match written YAML value"); |
| 51 | + } |
| 52 | + |
| 53 | + @Test |
| 54 | + void reloadPicksUpChanges(@TempDir Path tempDir) throws IOException { |
| 55 | + Path configFile = tempDir.resolve("config.yml"); |
| 56 | + Files.writeString(configFile, validYaml("server-a")); |
| 57 | + |
| 58 | + var manager = new ConfigManager<>(tempDir, BackendsConfig.class); |
| 59 | + assertTrue(manager.load(), "initial load should succeed"); |
| 60 | + assertTrue("server-a".equals(manager.current().clientId()), |
| 61 | + "clientId should be server-a after initial load"); |
| 62 | + |
| 63 | + Files.writeString(configFile, validYaml("server-b")); |
| 64 | + assertTrue(manager.reload(), "reload should succeed"); |
| 65 | + assertTrue("server-b".equals(manager.current().clientId()), |
| 66 | + "clientId should be server-b after reload"); |
| 67 | + } |
| 68 | + |
| 69 | + @Test |
| 70 | + void currentReturnsNullBeforeLoad(@TempDir Path tempDir) { |
| 71 | + var manager = new ConfigManager<>(tempDir, BackendsConfig.class); |
| 72 | + |
| 73 | + assertNull(manager.current(), "current() should be null before any load"); |
| 74 | + } |
| 75 | + |
| 76 | + @Test |
| 77 | + void loadWithMissingRequiredFieldFallsBackToDefault(@TempDir Path tempDir) throws IOException { |
| 78 | + Path configFile = tempDir.resolve("config.yml"); |
| 79 | + Files.writeString(configFile, "client-id: partial-server\n"); |
| 80 | + |
| 81 | + var manager = new ConfigManager<>(tempDir, BackendsConfig.class); |
| 82 | + manager.load(); |
| 83 | + |
| 84 | + assertNotNull(manager.current(), "current() should not be null even with partial YAML"); |
| 85 | + assertNotNull(manager.current().clientId(), |
| 86 | + "clientId should be populated from partial YAML or defaults"); |
| 87 | + } |
| 88 | + |
| 89 | + private static String validYaml(String clientId) { |
| 90 | + return """ |
| 91 | + client-id: "%s" |
| 92 | + endpoint-type: WEBSOCKET |
| 93 | + endpoints: |
| 94 | + websocket: |
| 95 | + host: "127.0.0.1" |
| 96 | + port: 8765 |
| 97 | + redis: |
| 98 | + host: "127.0.0.1" |
| 99 | + port: 6379 |
| 100 | + username: "" |
| 101 | + password: "" |
| 102 | + security: |
| 103 | + tls-mode: TOFU |
| 104 | + tls-pin: "" |
| 105 | + secret: "my-real-secret" |
| 106 | + timeouts: |
| 107 | + auth-timeout: 5 |
| 108 | + reconnect-timeout: 60 |
| 109 | + reconnect-interval: 5 |
| 110 | + debug: false |
| 111 | + """.formatted(clientId); |
| 112 | + } |
| 113 | +} |
0 commit comments