使用Maven+Byteman+JUnit测试Hadoop时遇BMUnit配置栈异常
解决BMUnit配置异常:method configuration pushed without prior pop
问题场景
通过Maven整合Byteman与JUnit测试Hadoop项目,已配置相关依赖、测试类和Byteman规则脚本,运行测试时抛出以下异常:
[ERROR] testPathResolveToLinkFallBack(org.apache.hadoop.fs.viewfs.TestNestedMountPoint) Time elapsed: 22.084 s <<< ERROR! java.lang.Exception: BMUnit method configuration pushed without prior method configuration pop! at org.jboss.byteman.contrib.bmunit.BMUnitConfigState.pushConfigurationState(BMUnitConfigState.java:750) at org.jboss.byteman.contrib.bmunit.BMUnitRunner$6.evaluate(BMUnitRunner.java:261) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.apache.maven.surefire.junitcore.pc.Scheduler$1.run(Scheduler.java:405) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:750)
相关配置信息
Maven依赖配置
<dependencies> <dependency> <groupId>com.byteman</groupId> <artifactId>myhelper</artifactId> <!-- <scope>test</scope> --> <version>1.0.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> <version>4.13.2</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman</artifactId> <!-- <scope>test</scope> --> <version>4.0.20</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman-submit</artifactId> <scope>test</scope> <version>4.0.20</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman-install</artifactId> <scope>test</scope> <version>4.0.20</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman-bmunit</artifactId> <scope>test</scope> <version>4.0.20</version> <exclusions> <exclusion> <groupId>org.testng</groupId> <artifactId>testng</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
测试类代码片段
@org.junit.runner.RunWith(org.jboss.byteman.contrib.bmunit.BMUnitRunner.class) @org.jboss.byteman.contrib.bmunit.BMUnitConfig(loadDirectory="target/test-classes") @org.jboss.byteman.contrib.bmunit.BMScript(value="check.btm") public class TestNestedMountPoint { private InodeTree inodeTree; private Configuration conf; private String mtName; private URI fsUri; static class TestNestMountPointFileSystem { public URI getUri() { return uri; } private URI uri; TestNestMountPointFileSystem(URI uri) { this.uri = uri; } } ... }
Byteman规则脚本(check.btm)片段
RULE 8b6addaa-abcb-4c5a-b82a-88286b61da08 CLASS java.util.ArrayDeque METHOD java.lang.Object getLast() COMPILE HELPER com.byteman.MyHelper AT ENTRY BIND value: String = Long.toString(System.currentTimeMillis()) +" " + Thread.currentThread().toString().replaceAll(" ","") + " " + Integer.toString(System.identityHashCode($0)) +" r =" + formatStack().toString().replaceAll("\n"," ") + "=\n" ; IF true DO writeLog(value); ENDRULE RULE f92a477e-28f9-405b-8684-e411f0f3e1aa CLASS java.util.ArrayDeque METHOD java.lang.Object getLast() COMPILE HELPER com.byteman.MyHelper AT EXIT BIND value: String = Long.toString(System.currentTimeMillis()) +" " + Thread.currentThread().toString().replaceAll(" ","") + " " + Integer.toString(System.identityHashCode($0)) +" r =" + formatStack().toString().replaceAll("\n"," ") + "=\n" ; IF true DO writeLog(value); ENDRULE ...
解决方案
该异常由BMUnit配置状态栈管理不当导致,以下是几种有效修复方式:
1. 合并类级别注解,避免重复配置
@BMUnitConfig支持直接通过scripts属性指定规则脚本,无需单独使用@BMScript注解,减少配置冲突:
@RunWith(BMUnitRunner.class) @BMUnitConfig(loadDirectory="target/test-classes", scripts = {"check.btm"}) public class TestNestedMountPoint { // 原有代码保持不变 }
2. 配置自动清理策略
在@BMUnitConfig中添加clearPolicy,确保每个测试方法结束后清理所有Byteman规则,避免状态栈残留:
@RunWith(BMUnitRunner.class) @BMUnitConfig( loadDirectory="target/test-classes", scripts = {"check.btm"}, clearPolicy = BMUnitConfig.ClearPolicy.ALL ) public class TestNestedMountPoint { // 原有代码保持不变 }
3. 检查父类注解冲突
如果测试类继承了其他带有BMUnit注解的父类,子类重复配置会触发异常。此时可以:
- 移除子类的
@RunWith和类级别BMUnit注解,复用父类配置 - 调整父类的
clearPolicy为ALL,确保子类测试方法执行前清理残留配置
4. 升级Byteman版本
当前使用的4.0.20版本存在配置栈管理bug,升级到4.0.21及以上版本可修复该问题,修改Maven依赖中的版本号即可:
<dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman</artifactId> <!-- <scope>test</scope> --> <version>4.0.21</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman-submit</artifactId> <scope>test</scope> <version>4.0.21</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman-install</artifactId> <scope>test</scope> <version>4.0.21</version> </dependency> <dependency> <groupId>org.jboss.byteman</groupId> <artifactId>byteman-bmunit</artifactId> <scope>test</scope> <version>4.0.21</version> <exclusions> <exclusion> <groupId>org.testng</groupId> <artifactId>testng</artifactId> </exclusion> </exclusions> </dependency>
5. 移除方法级重复注解
检查所有测试方法,若存在重复的@BMScript或@BMUnitConfig注解,需移除,避免重复加载配置导致栈异常。
内容的提问来源于stack exchange,提问作者user8682225
相关产品推荐
相关产品推荐

