yeg
6 天以前 a04222c873e5e55f48c8d33b5c0bc46fa524ac8d
ruoyi-admin/src/test/java/com/battery/business/runtime/PushIngestLandingMigrationContractTest.java
@@ -35,6 +35,7 @@
public class PushIngestLandingMigrationContractTest
{
    private static final String PATH = "db/migration-final/V24__push_ingest_landing_table.sql";
    private static final String VENDOR_CHANNEL_NO_PATH = "db/migration-final/V25__ingest_vendor_channel_no.sql";
    private static final String ADAPTER = "j22";
    private static final Instant RECEIVED_AT = Instant.parse("2026-09-27T09:20:00Z");
@@ -50,7 +51,9 @@
        jdbc = new JdbcTemplate(source);
        // H2 无 MySQL 的 HEX();测试中补一个等价别名,生产 SQL 仍在 MySQL 上验证。
        jdbc.execute("create alias HEX for 'com.battery.business.runtime.PushIngestLandingMigrationContractTest.hexOf'");
        // 按顺序跑落地表相关的迁移,使内存库结构与生产库一致(V24 建表、V25 加来源通道号列)。
        ScriptUtils.executeSqlScript(keepAlive, new ClassPathResource(PATH));
        ScriptUtils.executeSqlScript(keepAlive, new ClassPathResource(VENDOR_CHANNEL_NO_PATH));
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(source);
@@ -78,6 +81,33 @@
                "select count(*) from t_device_ingest_record where voltage_v is null", Integer.class));
    }
    /**
     * 来源自己的通道叫法那条迁移:只加一个可空列,不写入任何数据;
     * 老行读出来是空(界面回退到「单元-通道」),新行可以带上来源软件里显示的通道号。
     */
    @Test
    void vendorChannelNoMigrationOnlyAddsANullableColumn()
    {
        String migration = resource(VENDOR_CHANNEL_NO_PATH);
        assertTrue(migration.contains("ADD COLUMN vendor_channel_no INT NULL"));
        assertFalse(migration.matches("(?s).*(INSERT|UPDATE|DELETE|DROP)\\b.*"));
        jdbc.update("insert into t_device_ingest_record(adapter_code, payload_kind, record_key, payload_json,"
                + " content_sha256, received_at_utc) values(?,?,?,?,?,?)", ADAPTER, "TOPOLOGY", "topology:26",
                "{\"channel\":26}", new byte[32], Timestamp.from(RECEIVED_AT));
        // 迁移在 setUp 里已按顺序执行过(V24 建表、V25 加列),这里只核对列的行为。
        assertNull(jdbc.queryForObject(
                "select vendor_channel_no from t_device_ingest_record where record_key = 'topology:26'",
                Integer.class));
        jdbc.update("update t_device_ingest_record set vendor_channel_no = ? where record_key = ?", 27,
                "topology:26");
        assertEquals(27, jdbc.queryForObject(
                "select vendor_channel_no from t_device_ingest_record where record_key = 'topology:26'",
                Integer.class));
        // 展示列不参与身份:唯一键仍只由来源行身份决定。
        assertEquals(1, jdbc.queryForObject("select count(*) from t_device_ingest_record", Integer.class));
    }
    @Test
    void repeatedPushIsIgnoredBySourceRowIdentityAndDifferentContentIsKept()
    {