You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为定时清理文件的StandardIntegrationFlow编写功能测试?

测试方案验证与Minio文件时间设置实现

测试方案合理性

你的测试思路完全合理,精准覆盖了核心业务场景:

  • 验证旧文件被删除、新文件保留的核心逻辑,完全匹配需求预期
  • 通过手动触发SourcePollingChannelAdapter替代等待cron表达式,大幅提升测试效率,避免不必要的时间等待
  • 测试前验证文件存在、测试后验证结果的流程,保证了测试的闭环性

需要注意的细节:

  • 测试时建议临时调整清理阈值(比如将配置中的清理天数改为1分钟或更短),避免测试依赖真实的10天时间窗口
  • 确保获取SourcePollingChannelAdapter时使用正确的ID(你的代码中是oldReceiptsCleanerPoller),可通过ApplicationContext.getBean()直接获取

在Minio中创建指定修改时间的文件

Minio支持通过上传时设置属性或HTTP头指定文件的Last-Modified时间,结合Spring Integration的SFTP模板或Minio原生SDK都可以实现:

方法1:通过Spring Integration SFTP模板设置

利用RecursiveSftpRemoteFileTemplate的execute方法,上传文件后修改其属性:

import org.springframework.integration.sftp.session.RecursiveSftpRemoteFileTemplate
import java.io.ByteArrayInputStream

// 假设已注入receiptSftpRemoteFileTemplate
private void createFileWithModifiedTime(String remotePath, long modifiedTimestamp) {
    receiptSftpRemoteFileTemplate.execute(session -> {
        // 上传文件内容
        session.write(new ByteArrayInputStream("test content".getBytes()), remotePath)
        // 设置文件修改时间
        def attrs = new HashMap<String, Object>()
        attrs.put("last-modified", modifiedTimestamp)
        session.getClient().setStat(remotePath, attrs)
        return null
    })
}

方法2:使用Minio原生SDK设置

如果直接操作Minio存储,可通过PutObjectArgs的headers指定修改时间:

import io.minio.PutObjectArgs
import io.minio.MinioClient
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter

// 初始化Minio客户端
def minioClient = MinioClient.builder()
        .endpoint("http://your-minio-endpoint")
        .credentials("access-key", "secret-key")
        .build()

// 生成11天前的时间格式(符合HTTP头要求)
def oldFileTime = ZonedDateTime.now().minusDays(11)
def dateHeader = oldFileTime.format(DateTimeFormatter.RFC_1123_DATE_TIME)

// 上传旧文件并指定修改时间
minioClient.putObject(
        PutObjectArgs.builder()
                .bucket("test-bucket")
                .object("old-receipt.txt")
                .stream(new ByteArrayInputStream("old content".getBytes()), -1, 10485760)
                .headers(Map.of("Last-Modified", dateHeader))
                .build()
)

Spock测试完整示例

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.integration.endpoint.SourcePollingChannelAdapter
import org.springframework.integration.sftp.session.RecursiveSftpRemoteFileTemplate
import spock.lang.Specification
import java.time.Duration

class OldReceiptsCleanerSpec extends Specification {

    @Autowired
    private RecursiveSftpRemoteFileTemplate receiptSftpRemoteFileTemplate

    @Autowired
    private ApplicationContext applicationContext

    @Autowired
    private TestProperties testProperties // 自定义测试配置类,覆盖清理阈值

    def setup() {
        // 测试时临时设置清理阈值为1分钟
        testProperties.setRetentionDays(0)
        testProperties.setSftpPath("/test-receipts")
    }

    def "test old receipts are cleaned up while new ones remain"() {
        given: "准备两个测试文件:一个超过清理阈值,一个未超过"
        def remoteDir = testProperties.getSftpPath()
        def oldFilePath = "${remoteDir}/old-receipt.txt"
        def newFilePath = "${remoteDir}/new-receipt.txt"

        // 创建旧文件(修改时间为2分钟前)
        createFileWithModifiedTime(oldFilePath, System.currentTimeMillis() - Duration.ofMinutes(2).toMillis())
        // 创建新文件(修改时间为30秒前)
        createFileWithModifiedTime(newFilePath, System.currentTimeMillis() - Duration.ofSeconds(30).toMillis())

        expect: "初始状态下两个文件都存在"
        receiptSftpRemoteFileTemplate.exists(oldFilePath)
        receiptSftpRemoteFileTemplate.exists(newFilePath)

        when: "手动触发清理流程"
        SourcePollingChannelAdapter poller = applicationContext.getBean("oldReceiptsCleanerPoller", SourcePollingChannelAdapter)
        poller.start()
        sleep(1000) // 等待处理完成,可根据实际情况调整等待时间
        poller.stop()

        then: "旧文件被删除,新文件保留"
        !receiptSftpRemoteFileTemplate.exists(oldFilePath)
        receiptSftpRemoteFileTemplate.exists(newFilePath)
    }

    private void createFileWithModifiedTime(String remotePath, long modifiedTimestamp) {
        receiptSftpRemoteFileTemplate.execute(session -> {
            session.write(new ByteArrayInputStream("test content".getBytes()), remotePath)
            def attrs = new HashMap<String, Object>()
            attrs.put("last-modified", modifiedTimestamp)
            session.getClient().setStat(remotePath, attrs)
            return null
        })
    }
}

内容的提问来源于stack exchange,提问作者Vasilis Iak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:50:11