Elasticsearch源码在Intellij IDEA中调试
1. 代码导入
下载jdk11:https://www.azul.com/downloads/zulu/,设置JAVA_HOME等参数
创建文件~/.gradle/init.gradle
,加速三方包下载,内容如下
def aliyunRepo = 'http://maven.aliyun.com/nexus/content/groups/public/'
allprojects{
repositories {
all { ArtifactRepository repo ->
if(repo instanceof MavenArtifactRepository){
def url = repo.url.toString()
if (url.startsWith('https://repo1.maven.org/maven2') || url.startsWith('https://jcenter.bintray.com/') || url.startsWith('https://repo.maven.apache.org/maven2/')) {
project.logger.warn "Repository ${repo.url} removed."
remove repo
}
}
}
maven { url aliyunRepo }
}
buildscript {
repositories {
all { ArtifactRepository repo ->
if(repo instanceof MavenArtifactRepository){
def url = repo.url.toString()
if (url.startsWith('https://plugins.gradle.org/')) {
project.logger.warn "Build Script Repository ${repo.url} removed."
remove repo
}
}
}
maven { url aliyunRepo }
}
}
}
下载代码:[email protected]:elastic/elasticsearch.git,在代码目录执行
我们切换到分支v6.6.1
git checkout v6.6.1
./gradlew idea
打开IDEA,选择Import Project,打开代码目录
选择Gradle,下一步
选择User default gradle wrapper (recommended)
,Gradle JVM选择jdk11
,点击结束
代码开始编译,等待即可
2. 打包
源码调试是需要ES的Release包的,我们先对ES源码进行编译打包
在代码目录下执行
./gradlew assemble
执行完成后,生成的ES包在~/Project/src-code/elasticsearch/distribution/archives/tar/build/distributions/elasticsearch-6.6.1-SNAPSHOT.tar.gz
,我们直接解压得到~/Project/src-code/elasticsearch/distribution/archives/tar/build/distributions/elasticsearch-6.6.1-SNAPSHOT
,下面在IDEA中调试Elasticsearch需要用到。
在~/Project/src-code/elasticsearch/distribution/archives/tar/build/distributions/elasticsearch-6.6.1-SNAPSHOT/config
下创建java.policy文件,内容如下
grant {
// permission java.security.AllPermission;
permission java.lang.RuntimePermission "createClassLoader";
permission org.elasticsearch.ThreadPermission "modifyArbitraryThreadGroup";
permission org.elasticsearch.ThreadPermission "modifyArbitraryThread";
permission javax.management.MBeanTrustPermission "register";
permission javax.management.MBeanServerPermission "createMBeanServer";
permission javax.management.MBeanPermission "-#-[-]", "queryNames";
permission javax.management.MBeanTrustPermission "register";
};
3. IDEA启动Elasticsearch
Elasticsearch的启动类为org.elasticsearch.bootstrap.Elasticsearch
,在启动之前,需要添加一些JVM参数如下
-Des.path.conf=${user.home}/Project/src-code/elasticsearch/distribution/archives/tar/build/distributions/elasticsearch-6.6.1-SNAPSHOT/config
-Des.path.data=${user.home}/Project/src-code/elasticsearch/distribution/archives/tar/build/distributions/elasticsearch-6.6.1-SNAPSHOT/data
-Des.path.home=${user.home}/Project/src-code/elasticsearch/distribution/archives/tar/build/distributions/elasticsearch-6.6.1-SNAPSHOT/
-Djava.security.policy=${es.path.conf}/java.policy
-ea
这边的${user.home}
必须要用用户自己的home目录替换不能用占位符。
这边特别需要注意,必须要勾选Include dependencies with "Provided" scope
点击启动Debug
4. 单元测试
1)在命令行中执行单元测试
在Elasticsearch源码目录下执行./gradle test
就会运行所有单元测试,所有单元测试只有在Linux环境下才能全部执行成功。
如果需要执行单个测试的话,执行
./gradlew {模块名}:test -Dtests.class="{测试类,支持通配符}"
如执行org.elasticsearch.index.analysis.AnalysisICUFactoryTests
,可以这么写
./gradlew :plugins:analysis-icu:test -Dtests.class="*.AnalysisICUFactoryTests"
具体的使用可以参看源码中的TESTING.asciidoc
文件,但是文档中有错误,如上述的执行单个测试,文档中关于执行单个case的例子,不应该使用./gradlew test "-Dtests.class=*.ClassName"
,而应该使用./gradlew {模块名}:test "-Dtests.class=*.ClassName"
复现失败的的case
Elasticsearch中有的单元测试有许多是带随机值的,如org.elasticsearch.cli.EvilCommandTests#testCommandShutdownHook
,其中的局部变量shouldThrow
就是随机生成的,也就是说某些测试在某些时候运行时可以正常通过的,而有些时候不行,gradle这边也在失败的测试用例后打印出如何复现的命令,如我们在org.elasticsearch.cli.EvilCommandTests#testCommandShutdownHook
中,添加如下几行
if (randomBoolean()) {
assertThat(false, is(true));
}
也就是说该case有1/2的概率执行失败,我们执行下面的命令
./gradlew :qa:evil-tests:test -Dtests.class="*.EvilCommandTests"
如果执行失败,在输出中可以找到如何复现的相关信息,如下
2> REPRODUCE WITH: ./gradlew :qa:evil-tests:test -Dtests.seed=41A154F0A82EA9BE -Dtests.class=org.elasticsearch.cli.EvilCommandTests -Dtests.method="testCommandShutdownHook" -Dtests.security.manager=false -Dtests.locale=ce -Dtests.timezone=Antarctica/Casey
给出了复现需要的一些参数,如随机种子、locale、时区等信息
直接执行
./gradlew :qa:evil-tests:test -Dtests.seed=41A154F0A82EA9BE -Dtests.class=org.elasticsearch.cli.EvilCommandTests -Dtests.method="testCommandShutdownHook" -Dtests.security.manager=false -Dtests.locale=ce -Dtests.timezone=Antarctica/Casey
2)在IDEA中执行单元测试
Elasticsearch的单元测试相关代码基本在对应子模块的src/test下,这边以server模块的org.elasticsearch.search.SearchHitsTests
为例,如果点击类左边的直接执行的话可能会报如下的错误
> Failed to apply plugin [id 'elasticsearch.build']
> JAVA_HOME must be set to build Elasticsearch
这是因为IDEA默认使用了gradle的环境进行单元测试,但是获取不到JAVA_HOME环境变量,这边需要配置一下
点击,Build, Execution, Deployment->Build Tools->Gradle->Runner,选择Platform Test Runner,点击应用。这样就可以在IDEA中执行与调试单元测试了。
复现失败的的case
在IDEA中执行测试用例同样会配到用例执行失败的问题,加入与"在命令行中执行单元测试"中一样,需要复现一些失败的case,我们在org.elasticsearch.search.SearchHitsTests
中添加一个case
@Test
public void randomFail() {
if (randomBoolean()) {
assertThat(true, is(false));
}
}
如果执行失败,同样会输出如何复现的相关命令
REPRODUCE WITH: ./gradlew null -Dtests.seed=D751B7B1CC87B62F -Dtests.class=org.elasticsearch.search.SearchHitsTests -Dtests.method="randomFail" -Dtests.locale=en-GM -Dtests.timezone=Greenwich
这边只需要将后面的JVM参数添加到IDEA中即可