Compare commits

...

4 Commits

Author SHA1 Message Date
金戟
5904ad99cb release v0.6.2 2021-04-07 21:38:24 +08:00
金戟
74fbc5b53f support configure file 2021-04-07 09:40:20 +08:00
金戟
f6b5bab250 manual generated serialVersionUID not works 2021-04-07 00:05:29 +08:00
金戟
f2feb3cc68 more precise omni handler filter 2021-04-06 23:08:30 +08:00
23 changed files with 153 additions and 30 deletions

View File

@@ -13,8 +13,8 @@ repositories {
dependencies {
testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
testImplementation('com.alibaba.testable:testable-all:0.6.1')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
testImplementation('com.alibaba.testable:testable-all:0.6.2')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
}
tasks.withType(JavaCompile) {

View File

@@ -12,7 +12,7 @@
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>5.6.2</junit.version>
<testable.version>0.6.1</testable.version>
<testable.version>0.6.2</testable.version>
</properties>
<dependencies>

View File

@@ -0,0 +1 @@
omni.constructor.enhance.enable = true

View File

@@ -16,8 +16,8 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.junit.jupiter:junit-jupiter:5.6.2")
testImplementation("com.alibaba.testable:testable-all:0.6.1")
testAnnotationProcessor("com.alibaba.testable:testable-processor:0.6.1")
testImplementation("com.alibaba.testable:testable-all:0.6.2")
testAnnotationProcessor("com.alibaba.testable:testable-processor:0.6.2")
}
tasks.withType<KotlinCompile> {

View File

@@ -14,7 +14,7 @@
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>5.6.2</junit.version>
<testable.version>0.6.1</testable.version>
<testable.version>0.6.2</testable.version>
</properties>
<dependencies>

View File

@@ -0,0 +1 @@
omni.constructor.enhance.enable = true

View File

@@ -14,8 +14,8 @@ repositories {
dependencies {
testImplementation 'org.codehaus.groovy:groovy-all:3.0.7'
testImplementation 'org.spockframework:spock-core:2.0-M5-groovy-3.0'
testImplementation('com.alibaba.testable:testable-all:0.6.1')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
testImplementation('com.alibaba.testable:testable-all:0.6.2')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
}
tasks.withType(JavaCompile) {

View File

@@ -12,7 +12,7 @@
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<testable.version>0.6.1</testable.version>
<testable.version>0.6.2</testable.version>
</properties>
<dependencyManagement>

View File

@@ -1,8 +1,13 @@
# Release Note
## 0.6.2
- support setup global testable agent configure via properties file
- disable OmniConstructor bytecode enhancement by default
- fix a `Spring` framework compatibility issue with OmniConstructor
## 0.6.1
- generate mock scanning log file automatically, for self-troubleshooting
- fix a `Spock` test frame compatibility issue
- fix a `Spock` test framework compatibility issue
- fix a `Gradle` unit test runtime compatibility issue
## 0.6.0

View File

@@ -16,7 +16,7 @@ It is recommended to add a `property` field that identifies the TestableMock ver
```xml
<properties>
<testable.version>0.6.1</testable.version>
<testable.version>0.6.2</testable.version>
</properties>
```
@@ -63,8 +63,8 @@ Add dependence of `TestableMock` in `build.gradle` file:
```groovy
dependencies {
testImplementation('com.alibaba.testable:testable-all:0.6.1')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
testImplementation('com.alibaba.testable:testable-all:0.6.2')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
}
```

View File

@@ -1,5 +1,10 @@
# Release Note
## 0.6.2
- 支持通过Properties文件配置TestableAgent
- 默认禁用OmniConstructor相关的字节码增强
- 修复OmniConstructor与`Spring`框架的兼容问题issue-129
## 0.6.1
- 自动生成Mock扫描过程日志文件便于自助排查问题
- 修复一处`Spock`测试框架的兼容问题 (issue-121)

View File

@@ -16,7 +16,7 @@
```xml
<properties>
<testable.version>0.6.1</testable.version>
<testable.version>0.6.2</testable.version>
</properties>
```
@@ -63,8 +63,8 @@
```groovy
dependencies {
testImplementation('com.alibaba.testable:testable-all:0.6.1')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
testImplementation('com.alibaba.testable:testable-all:0.6.2')
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
}
```

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-parent</artifactId>
<version>0.6.1</version>
<version>0.6.2</version>
<relativePath>../testable-parent</relativePath>
</parent>
<artifactId>testable-agent</artifactId>

View File

@@ -1,5 +1,6 @@
package com.alibaba.testable.agent;
import com.alibaba.testable.agent.config.PropertiesParser;
import com.alibaba.testable.agent.transformer.TestableClassTransformer;
import com.alibaba.testable.agent.util.GlobalConfig;
import com.alibaba.testable.core.model.MockScope;
@@ -21,13 +22,15 @@ public class PreMain {
private static final String DUMP_PATH = "dumpPath";
private static final String PKG_PREFIX = "pkgPrefix";
private static final String MOCK_SCOPE = "mockScope";
private static final String CONFIG_FILE = "configFile";
private static final String EQUAL = "=";
private static boolean enhanceThreadLocal = false;
private static String configFilePath = null;
public static void premain(String agentArgs, Instrumentation inst) {
parseArgs(agentArgs);
new PropertiesParser().parseFile(configFilePath);
GlobalConfig.setupLogRootPath();
if (enhanceThreadLocal) {
if (GlobalConfig.isEnhanceThreadLocal()) {
// add transmittable thread local transformer
TtlAgent.premain(agentArgs, inst);
}
@@ -56,11 +59,13 @@ public class PreMain {
GlobalConfig.setPkgPrefix(v);
} else if (k.equals(MOCK_SCOPE)) {
GlobalConfig.setDefaultMockScope(MockScope.of(v));
} else if (k.equals(CONFIG_FILE)) {
configFilePath = v;
}
} else {
// parameter with single value
if (a.equals(USE_THREAD_POOL)) {
enhanceThreadLocal = true;
GlobalConfig.setEnhanceThreadLocal(true);
}
}
}

View File

@@ -0,0 +1,70 @@
package com.alibaba.testable.agent.config;
import com.alibaba.testable.agent.util.GlobalConfig;
import com.alibaba.testable.agent.util.PathUtil;
import com.alibaba.testable.core.model.MockScope;
import com.alibaba.testable.core.util.LogUtil;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Properties;
import static com.alibaba.testable.agent.constant.ConstPool.PROPERTY_USER_DIR;
public class PropertiesParser {
private static final String DEFAULT_CONFIG_FILE = "src/test/resources/testable.properties";
private static final String LOG_LEVEL = "log.level";
private static final String LOG_FILE = "log.file";
private static final String DUMP_PATH = "dump.path";
private static final String PKG_PREFIX_WHITELIST = "custom.pkgPrefix.whiteList";
private static final String DEFAULT_MOCK_SCOPE = "mock.scope.default";
private static final String ENABLE_THREAD_POOL = "thread.pool.enhance.enable";
private static final String ENABLE_OMNI_INJECT = "omni.constructor.enhance.enable";
public void parseFile(String configFilePath) {
String path = (configFilePath == null) ? DEFAULT_CONFIG_FILE : configFilePath;
String fullPath = PathUtil.join(System.getProperty(PROPERTY_USER_DIR), path);
Properties pps = new Properties();
try {
InputStream in = new BufferedInputStream(new FileInputStream(fullPath));
pps.load(in);
LogUtil.verbose("Loaded configure file %s", fullPath);
} catch (IOException e) {
if (configFilePath == null) {
LogUtil.verbose("No configure file found, skip.");
} else {
LogUtil.warn("No configure file found at %s", fullPath);
}
return;
}
parsePropertiesContent(pps);
}
private void parsePropertiesContent(Properties pps) {
Enumeration<?> en = pps.propertyNames();
while(en.hasMoreElements()) {
String k = (String)en.nextElement();
String v = pps.getProperty(k);
if (k.equals(LOG_LEVEL)) {
GlobalConfig.setLogLevel(v);
} else if (k.equals(LOG_FILE)) {
GlobalConfig.setLogFile(v);
} else if (k.equals(DUMP_PATH)) {
GlobalConfig.setDumpPath(v);
} else if (k.equals(PKG_PREFIX_WHITELIST)) {
GlobalConfig.setPkgPrefix(v);
} else if (k.equals(DEFAULT_MOCK_SCOPE)) {
GlobalConfig.setDefaultMockScope(MockScope.of(v));
} else if (k.equals(ENABLE_THREAD_POOL)) {
GlobalConfig.setEnhanceThreadLocal(Boolean.parseBoolean(v));
} else if (k.equals(ENABLE_OMNI_INJECT)) {
GlobalConfig.setEnhanceOmniConstructor(Boolean.parseBoolean(v));
}
}
}
}

View File

@@ -24,6 +24,8 @@ public class OmniClassHandler extends BaseClassHandler {
private static final String METHOD_START = "(";
private static final String VOID_METHOD_END = ")V";
private static final String VOID_METHOD = "()V";
private static final String ENABLE_CONFIGURATION_PROPERTIES
= "Lorg/springframework/boot/context/properties/EnableConfigurationProperties;";
private static final String[] JUNIT_TEST_ANNOTATIONS = new String[] {
JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST
@@ -31,9 +33,13 @@ public class OmniClassHandler extends BaseClassHandler {
@Override
protected void transform(ClassNode cn) {
if (isInterface(cn) || isJunitTestClass(cn) || isUninstantiableClass(cn)) {
if (isInterface(cn) || isJunitTestClass(cn) || isUninstantiableClass(cn) || hasSpecialAnnotation(cn)) {
return;
}
addConstructorWithNullTypeParameter(cn);
}
private void addConstructorWithNullTypeParameter(ClassNode cn) {
MethodNode constructor = new MethodNode(ACC_PUBLIC, CONSTRUCTOR,
METHOD_START + ClassUtil.toByteCodeClassName(NULL_TYPE) + VOID_METHOD_END, null, null);
LabelNode start = new LabelNode(new Label());
@@ -51,6 +57,18 @@ public class OmniClassHandler extends BaseClassHandler {
cn.methods.add(constructor);
}
private boolean hasSpecialAnnotation(ClassNode cn) {
if (cn.visibleAnnotations == null) {
return false;
}
for (AnnotationNode an : cn.visibleAnnotations) {
if (an.desc.equals(ENABLE_CONFIGURATION_PROPERTIES)) {
return true;
}
}
return false;
}
private boolean isUninstantiableClass(ClassNode cn) {
// if the class has no even default constructor, skip it
for (MethodNode mn : cn.methods) {

View File

@@ -40,8 +40,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
/**
* Just avoid spend time to scan those surely non-user classes, should keep these lists as tiny as possible
*/
private final String[] BLACKLIST_PREFIXES = new String[] { "sun/", "com/sun/", "org/gradle/",
"org/springframework/boot/autoconfigure/" };
private final String[] BLACKLIST_PREFIXES = new String[] { "sun/", "com/sun/", "org/gradle/" };
public MockClassParser mockClassParser = new MockClassParser();
@@ -53,7 +52,8 @@ public class TestableClassTransformer implements ClassFileTransformer {
return null;
}
LogUtil.verbose("Handle class: " + className);
byte[] bytes = new OmniClassHandler().getBytes(classFileBuffer);
byte[] bytes = GlobalConfig.isEnhanceOmniConstructor() ?
new OmniClassHandler().getBytes(classFileBuffer) : classFileBuffer;
ClassNode cn = ClassUtil.getClassNode(className);
if (cn != null) {
return transformMock(bytes, cn);

View File

@@ -25,6 +25,8 @@ public class GlobalConfig {
private static String dumpPath = null;
private static String pkgPrefix = null;
private static MockScope defaultMockScope = MockScope.GLOBAL;
private static boolean enhanceThreadLocal = false;
private static boolean enhanceOmniConstructor = false;
public static void setLogLevel(String level) {
if (level.equals(MUTE)) {
@@ -78,4 +80,20 @@ public class GlobalConfig {
LogUtil.setGlobalLogPath(PathUtil.join(System.getProperty(PROPERTY_USER_DIR), logFile));
}
}
public static void setEnhanceThreadLocal(boolean enabled) {
enhanceThreadLocal = enabled;
}
public static boolean isEnhanceThreadLocal() {
return enhanceThreadLocal;
}
public static void setEnhanceOmniConstructor(boolean enabled) {
enhanceOmniConstructor = enabled;
}
public static boolean isEnhanceOmniConstructor() {
return enhanceOmniConstructor;
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-parent</artifactId>
<version>0.6.1</version>
<version>0.6.2</version>
<relativePath>../testable-parent</relativePath>
</parent>
<artifactId>testable-all</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-parent</artifactId>
<version>0.6.1</version>
<version>0.6.2</version>
<relativePath>../testable-parent</relativePath>
</parent>
<artifactId>testable-core</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-parent</artifactId>
<version>0.6.1</version>
<version>0.6.2</version>
<relativePath>../testable-parent</relativePath>
</parent>
<artifactId>testable-maven-plugin</artifactId>

View File

@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-parent</artifactId>
<version>0.6.1</version>
<version>0.6.2</version>
<packaging>pom</packaging>
<name>testable-parent</name>
<description>Unit test enhancement toolkit</description>
@@ -42,7 +42,7 @@
<plugin.gpg.version>1.6</plugin.gpg.version>
<plugin.staging.version>1.6.8</plugin.staging.version>
<plugin.maven.version>3.6.0</plugin.maven.version>
<testable.version>0.6.1</testable.version>
<testable.version>0.6.2</testable.version>
</properties>
<profiles>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.alibaba.testable</groupId>
<artifactId>testable-parent</artifactId>
<version>0.6.1</version>
<version>0.6.2</version>
<relativePath>../testable-parent</relativePath>
</parent>
<artifactId>testable-processor</artifactId>