Browse Source

Add real-context integration test for LTS 4.2.2.3 migration

pull/15808/head
Viacheslav Klimov 3 months ago
parent
commit
dfe1c046f8
Failed to extract signature
  1. 144
      application/src/test/java/org/thingsboard/server/service/install/lts/LtsMigrationIntegrationTest.java

144
application/src/test/java/org/thingsboard/server/service/install/lts/LtsMigrationIntegrationTest.java

@ -0,0 +1,144 @@
/**
* Copyright © 2016-2026 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.install.lts;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.WidgetTypeId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import java.util.List;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@DaoSqlTest
public class LtsMigrationIntegrationTest extends AbstractControllerTest {
private static final long V_4_2_2_2 = 4_002_002_002L;
private static final long V_4_2_2_3 = 4_002_002_003L;
private static final String OBSOLETE_ALIAS = "air_quality";
@Autowired
private LtsMigrationService ltsMigrationService;
@Autowired
private WidgetsBundleService widgetsBundleService;
@Autowired
private WidgetTypeService widgetTypeService;
@Autowired
private JdbcTemplate jdbcTemplate;
private Long originalSchemaVersion;
private WidgetsBundleId bundleId;
private WidgetTypeId widgetTypeId;
@Before
public void setUp() {
// The test-context DB (DaoSqlTest) creates tb_schema_settings empty, so ensure the baseline
// version row a real installed DB always has exists before driving the migration.
originalSchemaVersion = jdbcTemplate.query("SELECT schema_version FROM tb_schema_settings",
rs -> rs.next() ? rs.getLong(1) : null);
if (originalSchemaVersion == null) {
jdbcTemplate.execute("INSERT INTO tb_schema_settings (schema_version, product) VALUES (" + V_4_2_2_2 + ", 'CE')");
}
// Seed an obsolete system widget bundle with one (non-deprecated) widget type linked to it.
WidgetsBundle bundle = new WidgetsBundle();
bundle.setTenantId(TenantId.SYS_TENANT_ID);
bundle.setAlias(OBSOLETE_ALIAS);
bundle.setTitle("Air quality");
bundleId = widgetsBundleService.saveWidgetsBundle(bundle).getId();
WidgetTypeDetails type = new WidgetTypeDetails();
type.setTenantId(TenantId.SYS_TENANT_ID);
type.setFqn("air_quality_sample_" + UUID.randomUUID());
type.setName("Air quality sample");
type.setDescriptor(JacksonUtil.fromString("{ \"type\": \"latest\" }", JsonNode.class));
WidgetTypeDetails saved = widgetTypeService.saveWidgetType(type);
widgetTypeId = saved.getId();
widgetTypeService.updateWidgetsBundleWidgetFqns(TenantId.SYS_TENANT_ID, bundleId, List.of(saved.getFqn()));
// Pretend the DB is at 4.2.2.2 so the 4.2.2.3 migration is in range (4.2.2.2, 4.2.2.3].
jdbcTemplate.execute("UPDATE tb_schema_settings SET schema_version = " + V_4_2_2_2);
}
@After
public void tearDown() {
// Restore the schema version (or drop the row we seeded) and clean up whatever the migration left behind.
if (originalSchemaVersion != null) {
jdbcTemplate.execute("UPDATE tb_schema_settings SET schema_version = " + originalSchemaVersion);
} else {
jdbcTemplate.execute("DELETE FROM tb_schema_settings");
}
if (widgetTypeId != null && widgetTypeService.findWidgetTypeDetailsById(TenantId.SYS_TENANT_ID, widgetTypeId) != null) {
widgetTypeService.deleteWidgetType(TenantId.SYS_TENANT_ID, widgetTypeId);
}
WidgetsBundle bundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(TenantId.SYS_TENANT_ID, OBSOLETE_ALIAS);
if (bundle != null) {
widgetsBundleService.deleteWidgetsBundle(TenantId.SYS_TENANT_ID, bundle.getId());
}
}
@Test
public void appliesSqlDeprecatesTypesDeletesBundleAndRecordsVersion() {
ltsMigrationService.applyMigrations("4.2.2.2", "4.2.2.3");
// 1. The version's SQL ran: iot_hub_installed_item table now exists.
assertTrue(tableExists("iot_hub_installed_item"));
// 2. The version was recorded.
assertEquals(Long.valueOf(V_4_2_2_3),
jdbcTemplate.queryForObject("SELECT schema_version FROM tb_schema_settings", Long.class));
// 3. The obsolete bundle entity was deleted.
assertNull(widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(TenantId.SYS_TENANT_ID, OBSOLETE_ALIAS));
// 4. The widget type was KEPT and marked deprecated.
WidgetTypeDetails type = widgetTypeService.findWidgetTypeDetailsById(TenantId.SYS_TENANT_ID, widgetTypeId);
assertNotNull(type);
assertTrue(type.isDeprecated());
}
@Test
public void reRunFromCurrentVersionIsNoOp() {
ltsMigrationService.applyMigrations("4.2.2.2", "4.2.2.3");
// Re-running from the now-current version selects an empty range — nothing changes, nothing throws.
ltsMigrationService.applyMigrations("4.2.2.3", "4.2.2.3");
assertEquals(Long.valueOf(V_4_2_2_3),
jdbcTemplate.queryForObject("SELECT schema_version FROM tb_schema_settings", Long.class));
assertNull(widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(TenantId.SYS_TENANT_ID, OBSOLETE_ALIAS));
assertTrue(widgetTypeService.findWidgetTypeDetailsById(TenantId.SYS_TENANT_ID, widgetTypeId).isDeprecated());
}
private boolean tableExists(String table) {
Boolean exists = jdbcTemplate.queryForObject(
"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = ?)", Boolean.class, table);
return Boolean.TRUE.equals(exists);
}
}
Loading…
Cancel
Save