OnecardDemo 用户全量同步分阶段耗时日志实施计划

For agentic workers: REQUIRED SUB-SKILL: Use executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 为用户全量同步记录总数请求、每批网络请求、XML解析、SQLite保存、单批总计和整轮总计耗时,写入现有本地日志且不修改数据库结构。

Architecture: CustomerSyncService 使用可注入的单调时间源和 SyncLogger 生成结构化 CUSTOMER_SYNC_* 事件;生产适配器转发到现有 ReaderLog,测试适配器收集事件。ServerOperationsActivity 只负责初始化日志,页面和 SQLite schema 保持不变。

Tech Stack: Java 8、JUnit 4、AndroidX Test、现有 ReaderLog/ReaderLogStore、Gradle


Task 1:同步计时与日志契约

Files:

CustomerSyncServiceTest 增加每次 nanoTime() 前进1毫秒的可控时间源和内存 SyncLogger。两批成功同步后断言:

CUSTOMER_SYNC_START
CUSTOMER_SYNC_COUNT_SUCCESS requestMs=1
CUSTOMER_SYNC_BATCH_START batch=1
CUSTOMER_SYNC_REQUEST_SUCCESS batch=1 requestMs=1 responseBytes>0
CUSTOMER_SYNC_PARSE_SUCCESS batch=1 records=2 parseMs=1
CUSTOMER_SYNC_SAVE_SUCCESS batch=1 saveMs=1 batchMs=7
...第二批同序列...
CUSTOMER_SYNC_SUCCESS elapsedMs>=0

Run: ./gradlew testDebugUnitTest --tests com.cpt.onecarddemo.customer.CustomerSyncServiceTest

Expected: 编译失败,提示 SyncLogger 或新构造器不存在。

新增:

public interface SyncLogger {
    void info(String event, String details);
    void error(String event, String details, Throwable throwable);
}

CustomerSyncService.TimeSource 明确为同时提供 currentTimeMillis()nanoTime();系统实现分别使用 System.currentTimeMillis()System.nanoTime()

在不改变原分页、解析、保存顺序的前提下记录:同步开始、总数请求、每批开始、请求成功、解析成功、保存成功和同步成功。responseBytes 使用 response.getRawXml().getBytes(StandardCharsets.UTF_8).length,只记录长度。

日志调用必须通过 safeInfo/safeError 包装并吞掉日志器自身异常,保证日志故障不改变同步结果。

分别让总数请求、分页请求、XML解析、仓库保存和完成清理失败,断言唯一的 CUSTOMER_SYNC_FAILURE 包含正确的 stage=count/request/parse/save/complete、当前批次、已保存数、stageMs 和总 elapsedMs;原有“前批保留、失败标记、不调用完成”断言继续成立。

用当前阶段变量和阶段开始的单调时间统一生成失败事件;异常消息不附加 SOAP 原文或任何用户字段值。

Run: ./gradlew testDebugUnitTest --tests com.cpt.onecarddemo.customer.CustomerSyncServiceTest

Expected: BUILD SUCCESSFUL,所有同步测试通过。

Task 2:接入现有本地日志

Files:

页面测试直接启动 ServerOperationsActivity 后断言 ReaderLog.getLogDirectory() 非空且目录名为 reader_logs,证明不依赖先进入主页面。

Run: ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.cpt.onecarddemo.ServerOperationsUiTest

Expected: 新用例失败,因为服务器页面尚未初始化 ReaderLog

ReaderLogSyncLogger.info/error 分别委托 ReaderLog.info/errorCustomerSyncService 公共构造器使用该适配器;包内测试构造器继续允许注入 fake logger。

ServerOperationsActivity.onCreate() 创建同步服务之前调用 ReaderLog.initialize(this),不增加控件、不修改按钮启用条件。

Run: ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.cpt.onecarddemo.ServerOperationsUiTest

Expected: 页面测试全部通过。

Task 3:文档、完整验证和安装

Files:

把设计状态改为“已实施,待现场全量同步验证”;协议文档记录所有事件、字段、日志目录、保留规则和敏感信息边界;变更记录写明 RED/GREEN、测试数量、构建、Lint、真机和安装结果。

Run: ./gradlew testDebugUnitTest assembleDebug assembleDebugAndroidTest lintDebug --rerun-tasks

Expected: BUILD SUCCESSFUL,JVM 测试0 failure、0 error,Lint 0 error。

Run: ./gradlew connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.cpt.onecarddemo.customer.SQLiteCustomerRepositoryTest,com.cpt.onecarddemo.ServerOperationsUiTest

Expected: 本次相关测试0 failure。

Run: adb install -r app/build/outputs/apk/debug/app-debug.apk

Expected: Success

用户执行一次全量同步,在“查看读卡日志”中搜索 CUSTOMER_SYNC_,确认每批耗时字段存在且非负;此步骤不由自动构建主动触发。

执行约束