Elasticsearch源码在Intellij IDEA中调试

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,打开代码目录
image.png
选择Gradle,下一步
image
选择User default gradle wrapper (recommended),Gradle JVM选择jdk11,点击结束
image
代码开始编译,等待即可
image

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
image

点击image.png启动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为例,如果点击类左边的image.png直接执行的话可能会报如下的错误

> Failed to apply plugin [id 'elasticsearch.build']
   > JAVA_HOME must be set to build Elasticsearch

这是因为IDEA默认使用了gradle的环境进行单元测试,但是获取不到JAVA_HOME环境变量,这边需要配置一下
点击image.png,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中即可
image.png

猜你喜欢

转载自yq.aliyun.com/articles/692633
今日推荐