diff --git a/application/src/main/java/org/thingsboard/server/service/install/lts/V4_3_1_2Migration.java b/application/src/main/java/org/thingsboard/server/service/install/lts/V4_3_1_2Migration.java index cc76184c04..cb5da78070 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/lts/V4_3_1_2Migration.java +++ b/application/src/main/java/org/thingsboard/server/service/install/lts/V4_3_1_2Migration.java @@ -18,6 +18,17 @@ package org.thingsboard.server.service.install.lts; import org.springframework.stereotype.Component; import org.thingsboard.server.queue.util.TbCoreComponent; +/** + * Registration-only migration with no {@link #apply()} (no data migration), kept intentionally. + *

+ * {@link LtsMigrationService} selects migrations from the injected {@link LtsMigration} beans, not from the + * on-disk {@code data/upgrade/lts//} directories. So this bean is what makes the runner discover + * version {@code 4.3.1.2} and execute its {@code data/upgrade/lts/4.3.1.2/schema_update.sql} (which adds + * {@code calculated_field.additional_info}). A directory holding a {@code schema_update.sql} but lacking a + * matching bean would be silently skipped. + *

+ * The dir/bean consistency (both ways) is guarded by a test in {@code LtsMigrationIntegrationTest}. + */ @Component @TbCoreComponent public class V4_3_1_2Migration implements LtsMigration { diff --git a/application/src/test/java/org/thingsboard/server/service/install/lts/LtsMigrationIntegrationTest.java b/application/src/test/java/org/thingsboard/server/service/install/lts/LtsMigrationIntegrationTest.java index 06c5f410a3..b6cf3178fc 100644 --- a/application/src/test/java/org/thingsboard/server/service/install/lts/LtsMigrationIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/service/install/lts/LtsMigrationIntegrationTest.java @@ -45,6 +45,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -174,6 +175,20 @@ public class LtsMigrationIntegrationTest extends AbstractControllerTest { jdbcTemplate.queryForObject("SELECT schema_version FROM tb_schema_settings", Long.class)); } + @Test + public void appliesSchemaForV4312AddsCalculatedFieldAdditionalInfo() { + // The test-context schema already ships calculated_field.additional_info, so drop it first to prove the + // 4.3.1.2 schema_update.sql (ALTER TABLE calculated_field ADD COLUMN IF NOT EXISTS additional_info) re-adds it. + jdbcTemplate.execute("ALTER TABLE calculated_field DROP COLUMN IF EXISTS additional_info"); + assertFalse(columnExists("calculated_field", "additional_info")); + + // Drive the runner over a range whose target (4.3.1.2) selects only the 4.3.1.2 migration. + ltsMigrationService.applyMigrations("4.3.1.1", "4.3.1.2"); + + // The 4.3.1.2 schema SQL ran: the column exists again. + assertTrue(columnExists("calculated_field", "additional_info")); + } + @Test public void migrationDirectoriesAndBeansStayInSyncBothWays() { Path ltsDir = Paths.get(installScripts.getDataDir(), "upgrade", "lts"); @@ -216,4 +231,11 @@ public class LtsMigrationIntegrationTest extends AbstractControllerTest { "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = ?)", Boolean.class, table); return Boolean.TRUE.equals(exists); } + + private boolean columnExists(String table, String column) { + Boolean exists = jdbcTemplate.queryForObject( + "SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = ? AND column_name = ?)", + Boolean.class, table, column); + return Boolean.TRUE.equals(exists); + } }