目前想每隔 10 分钟自动收集一次测试环境所有特性分支的当前覆盖率,并做合并操作,提高覆盖率收集效率和准确性。
但实际在合并后覆盖率的文件会持续膨胀,如果频繁合并会导致磁盘迅速变满。
合并入口:
org.jacoco.core.tools.ExecFileLoader#save
实际写入:
org.jacoco.core.data.ExecutionDataWriter#visitClassExecution
分析发现,当 append=true,则读取原来的覆盖率文件,并合并到目标覆盖率文件中,所以文件体积会一直变大。
在合并前,先读取一次原来的文件,提前做合并操作,待合并完后,不已追加写的方式写覆盖率文件,而是将覆盖率重新写入,这样写入的覆盖率就是合并后的了。
新建一个类,继承 ExecFileLoader,并覆盖 save 方法
public void save(final File file, boolean append) throws IOException {
if (file.exists()) {
final FileInputStream in = new FileInputStream(file);
final ExecutionDataReader reader = new ExecutionDataReader(in);
// 1. 读取目标覆盖率文件
ExecutionDataStore destExecDataStore = new ExecutionDataStore();
reader.setSessionInfoVisitor(new SessionInfoStore());
reader.setExecutionDataVisitor(destExecDataStore);
reader.read();
in.close();
// 2. 合并 新的覆盖率文件 和 目标覆盖文件
this.executionData.merge(destExecDataStore.getContents());
}
// 3. 不通过追加写的方式写入覆盖率
final FileOutputStream fileStream = new FileOutputStream(file, false);
// Avoid concurrent writes from other processes:
fileStream.getChannel().lock();
final OutputStream bufferedStream = new BufferedOutputStream(
fileStream);
try {
save(bufferedStream);
} finally {
bufferedStream.close();
}
}
merge 方法:
public void merge(Collection<ExecutionData> executionDataList) {
Map<Long, ExecutionData> mergeEntries = new HashMap<Long, ExecutionData>();
// executionDataList 为待合入的覆盖率文件
for (ExecutionData executionData : executionDataList) {
mergeEntries.put(executionData.getId(), executionData);
}
//
for (Long id : mergeEntries.keySet()) {
// this.entries 是后续实际要写入的覆盖率数据
// 1. 如果类id一致,表示类没有变动,则合并覆盖率
if (this.entries.containsKey(id)) {
ExecutionData merge = mergeEntries.get(id);
ExecutionData entry = this.entries.get(id);
entry.mergeProbes(merge.getProbes());
this.entries.put(id, entry);
} else {
// 2. 如果不存在,则有可能类被改过,将旧的覆盖率合并到新的
this.entries.put(id, mergeEntries.get(id));
}
}
}
mergeProbes 方法
public void mergeProbes(boolean[] probes) {
for (int i = 0; i < this.probes.length; i++) {
if (!this.probes[i] && probes[i]) {
this.probes[i] = probes[i];
}
}
}
最后,记得在 org.jacoco.cli.internal.commands.Merge 中,将 ExecFileLoader 替换为我们优化后的类
如此,无论是代码、覆盖率有无改动,每次合并都只会合并增量的部分,合并后的文件大小基本不会发生太大改变。