You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by li...@apache.org on 2021/01/15 02:00:25 UTC

[dubbo-samples] branch master updated: Suport test multi versions (#260)

This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-samples.git


The following commit(s) were added to refs/heads/master by this push:
     new 3e6551b  Suport test multi versions (#260)
3e6551b is described below

commit 3e6551b0d3cc771a930cc936e2fd8b12eb80690c
Author: gongdewei <ky...@qq.com>
AuthorDate: Fri Jan 15 10:00:13 2021 +0800

    Suport test multi versions (#260)
---
 .github/workflows/dubbo-2.yml                      | 370 +++++++++++++++++
 .github/workflows/dubbo-3.yml                      | 370 +++++++++++++++++
 .github/workflows/java-ci.yml                      | 455 ---------------------
 .github/workflows/nightly-dubbo-2.yml              | 374 +++++++++++++++++
 .github/workflows/nightly-dubbo-3.yml              | 374 +++++++++++++++++
 .gitignore                                         |   2 +-
 README.md                                          |  42 +-
 dubbo-samples-annotation/case-versions.conf        |   6 +
 dubbo-samples-api/case-versions.conf               |   6 +
 .../case-versions.conf                             |   6 +
 .../dubbo-samples-async-onerror/case-versions.conf |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../dubbo-samples-async-simple/case-versions.conf  |   6 +
 dubbo-samples-attachment/case-versions.conf        |   6 +
 dubbo-samples-basic/case-versions.conf             |   6 +
 dubbo-samples-cache/case-versions.conf             |   6 +
 dubbo-samples-callback/case-versions.conf          |   6 +
 dubbo-samples-chain/case-versions.conf             |   6 +
 dubbo-samples-compatible/case-versions.conf        |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 dubbo-samples-consul/case-versions.conf            |   6 +
 dubbo-samples-context/case-versions.conf           |   6 +
 dubbo-samples-default-config/case-versions.conf    |   6 +
 dubbo-samples-direct/case-versions.conf            |   6 +
 dubbo-samples-docker/case-versions.conf            |   6 +
 dubbo-samples-docker/pom.xml                       |   4 +-
 dubbo-samples-echo/case-versions.conf              |   6 +
 .../dubbo-samples-generic-call/case-versions.conf  |   6 +
 .../dubbo-samples-generic-impl/case-versions.conf  |   6 +
 .../dubbo-samples-generic-impl/pom.xml             |  17 +
 .../dubbo-samples-generic-type/case-versions.conf  |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../dubbo-samples-tagrouter/case-versions.conf     |   6 +
 dubbo-samples-group/case-versions.conf             |   6 +
 .../dubbo-samples-original/case-versions.conf      |   6 +
 dubbo-samples-grpc/dubbo-samples-original/pom.xml  |  10 +
 dubbo-samples-local/case-versions.conf             |   6 +
 dubbo-samples-merge/case-versions.conf             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 dubbo-samples-metrics/case-versions.conf           |   6 +
 dubbo-samples-mock/case-versions.conf              |   6 +
 dubbo-samples-monitor/case-versions.conf           |   6 +
 dubbo-samples-multi-registry/case-versions.conf    |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 dubbo-samples-notify/case-versions.conf            |   6 +
 dubbo-samples-protostuff/case-versions.conf        |   6 +
 dubbo-samples-rest/case-versions.conf              |   6 +
 dubbo-samples-sentinel/case-versions.conf          |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 .../case-versions.conf                             |   6 +
 dubbo-samples-spi-compatible/case-versions.conf    |   6 +
 .../case-versions.conf                             |   6 +
 dubbo-samples-spring-hystrix/case-versions.conf    |   6 +
 dubbo-samples-stub/case-versions.conf              |   6 +
 .../case-versions.conf                             |   6 +
 dubbo-samples-thrift/case-versions.conf            |   6 +
 dubbo-samples-transaction/case-versions.conf       |   6 +
 dubbo-samples-validation/case-versions.conf        |   6 +
 dubbo-samples-version/case-versions.conf           |   6 +
 dubbo-samples-zipkin/case-versions.conf            |   6 +
 dubbo-samples-zookeeper/case-versions.conf         |   6 +
 test/README.md                                     |   2 +-
 test/build-samples-and-test-image.sh               |  42 --
 .../dubbo/scenario/builder/ConfigurationImpl.java  |  50 ++-
 .../builder/{IConfiguration.java => FileUtil.java} |  50 +--
 .../dubbo/scenario/builder/IConfiguration.java     |   2 +-
 .../dubbo/scenario/builder/VersionMatcher.java     | 223 ++++++++++
 .../src/main/resources/logback.xml                 |  34 +-
 .../src/main/resources/scenario.sh                 |   2 +-
 .../dubbo/scenario/builder/VersionMatcherTest.java | 105 +++++
 test/dubbo-test-runner/build.sh                    |   5 +-
 test/dubbo-test-runner/src/docker/Dockerfile       |   3 +-
 .../apache/dubbo/test/runner/ClassLoaderUtils.java |  62 +++
 .../apache/dubbo/test/runner/TestRunnerMain.java   |   9 +-
 test/merge-test-results.sh                         |  20 +-
 test/prepare-test.sh                               |   2 +-
 test/quick-start_cn.md                             | 139 +++++--
 test/run-tests.sh                                  | 220 ++++++----
 97 files changed, 2698 insertions(+), 710 deletions(-)

diff --git a/.github/workflows/dubbo-2.yml b/.github/workflows/dubbo-2.yml
new file mode 100644
index 0000000..b492683
--- /dev/null
+++ b/.github/workflows/dubbo-2.yml
@@ -0,0 +1,370 @@
+name: Dubbo 2
+
+on:
+  pull_request:
+    paths:
+      - "**"
+  push:
+    paths:
+      - '**'
+
+env:
+  FORK_COUNT: 2
+  FAIL_FAST: 0
+  SHOW_ERROR_DETAIL: 1
+  BUILD_OPTS: -U --batch-mode --no-transfer-progress --settings ${{github.workspace}}/.mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
+  #multi-version size limit
+  VERSIONS_LIMIT: 4
+  CANDIDATE_VERSIONS: '
+    dubbo.version:2.7.8,2.7.9-SNAPSHOT;
+    spring.version:4.3.30.RELEASE;
+    spring-boot.version:1.5.22.RELEASE;
+    spring-boot.version:2.4.1;
+    '
+
+jobs:
+  build-samples:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build with Maven
+        run: |
+          ./mvnw $BUILD_OPTS
+
+  build-dubbo:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          repository: 'apache/dubbo'
+          ref: master
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+      - name: Get last git commit hash
+        id: git-hash
+        run: |
+          #compare dubbo commit id
+          last_commit_id=`git log --format="%H" -n 1`
+          echo "::set-output name=commit_id::$last_commit_id"
+          if [ -f ~/.m2/repository/org/apache/dubbo/dubbo-commit-id ];then
+            cache_commit_id=`cat ~/.m2/repository/org/apache/dubbo/dubbo-commit-id`
+          fi
+          if [ "$last_commit_id" == "$cache_commit_id" ];then
+            echo "::set-output name=cache-hit::true"
+          else
+            echo "::set-output name=cache-hit::false"
+          fi
+      - name: Cache local Maven repository
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK 8
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/setup-java@v1
+        with:
+          java-version: 8
+      - name: Build dubbo
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        run: |
+          ./mvnw -U --batch-mode --no-transfer-progress  clean install -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
+      - name: Update commit id
+        run: |
+          echo commit_id: ${{steps.git-hash.outputs.commit_id}}
+          echo ${{steps.git-hash.outputs.commit_id}} > ~/.m2/repository/org/apache/dubbo/dubbo-commit-id
+
+  prepare_test:
+    runs-on: ubuntu-latest
+    env:
+      #'JOB_COUNT' MUST match needs job list of 'test_result' job
+      JOB_COUNT: 5
+    steps:
+      - uses: actions/checkout@v1
+      - name: Prepare test list
+        run: |
+          cd test
+          bash ./prepare-test.sh
+      - name: Upload test list
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs
+
+  test_result:
+    #testjob list MUST match 'JOB_COUNT' of 'prepare_test' job
+    needs: [testjob_1,testjob_2,testjob_3,testjob_4,testjob_5]
+    if: always()
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    env:
+      JAVA_VER: ${{matrix.java}}
+    steps:
+      - uses: actions/checkout@v1
+      - name: Download test result
+        uses: actions/download-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/
+      - name: Merge test result - java ${{matrix.java}}
+        run: ./test/merge-test-results.sh
+
+  testjob_1:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_2:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_3:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_4:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_5:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
diff --git a/.github/workflows/dubbo-3.yml b/.github/workflows/dubbo-3.yml
new file mode 100644
index 0000000..776ddf1
--- /dev/null
+++ b/.github/workflows/dubbo-3.yml
@@ -0,0 +1,370 @@
+name: Dubbo 3
+
+on:
+  pull_request:
+    paths:
+      - "**"
+  push:
+    paths:
+      - '**'
+
+env:
+  FORK_COUNT: 2
+  FAIL_FAST: 0
+  SHOW_ERROR_DETAIL: 1
+  BUILD_OPTS: -U --batch-mode --no-transfer-progress --settings ${{github.workspace}}/.mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
+  #multi-version size limit
+  VERSIONS_LIMIT: 4
+  CANDIDATE_VERSIONS: '
+    dubbo.version:3.0.0-SNAPSHOT;
+    spring.version:4.3.30.RELEASE;
+    spring-boot.version:1.5.22.RELEASE;
+    spring-boot.version:2.4.1;
+    '
+
+jobs:
+  build-samples:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build with Maven
+        run: |
+          ./mvnw $BUILD_OPTS
+
+  build-dubbo:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          repository: 'apache/dubbo'
+          ref: master
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+      - name: Get last git commit hash
+        id: git-hash
+        run: |
+          #compare dubbo commit id
+          last_commit_id=`git log --format="%H" -n 1`
+          echo "::set-output name=commit_id::$last_commit_id"
+          if [ -f ~/.m2/repository/org/apache/dubbo/dubbo-commit-id ];then
+            cache_commit_id=`cat ~/.m2/repository/org/apache/dubbo/dubbo-commit-id`
+          fi
+          if [ "$last_commit_id" == "$cache_commit_id" ];then
+            echo "::set-output name=cache-hit::true"
+          else
+            echo "::set-output name=cache-hit::false"
+          fi
+      - name: Cache local Maven repository
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK 8
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/setup-java@v1
+        with:
+          java-version: 8
+      - name: Build dubbo
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        run: |
+          ./mvnw -U --batch-mode --no-transfer-progress  clean install -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
+      - name: Update commit id
+        run: |
+          echo commit_id: ${{steps.git-hash.outputs.commit_id}}
+          echo ${{steps.git-hash.outputs.commit_id}} > ~/.m2/repository/org/apache/dubbo/dubbo-commit-id
+
+  prepare_test:
+    runs-on: ubuntu-latest
+    env:
+      #'JOB_COUNT' MUST match needs job list of 'test_result' job
+      JOB_COUNT: 5
+    steps:
+      - uses: actions/checkout@v1
+      - name: Prepare test list
+        run: |
+          cd test
+          bash ./prepare-test.sh
+      - name: Upload test list
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs
+
+  test_result:
+    #testjob list MUST match 'JOB_COUNT' of 'prepare_test' job
+    needs: [testjob_1,testjob_2,testjob_3,testjob_4,testjob_5]
+    if: always()
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    env:
+      JAVA_VER: ${{matrix.java}}
+    steps:
+      - uses: actions/checkout@v1
+      - name: Download test result
+        uses: actions/download-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/
+      - name: Merge test result - java ${{matrix.java}}
+        run: ./test/merge-test-results.sh
+
+  testjob_1:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_2:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_3:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_4:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_5:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml
deleted file mode 100644
index 122dc6f..0000000
--- a/.github/workflows/java-ci.yml
+++ /dev/null
@@ -1,455 +0,0 @@
-name: Java CI
-
-on:
-  pull_request:
-    paths:
-      - "**"
-  push:
-    paths:
-      - '**'
-
-env:
-  FORK_COUNT: 2
-  FAIL_FAST: 0
-  SHOW_ERROR_DETAIL: 1
-  BUILD_OPTS: -U --no-transfer-progress --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build with Maven
-        run: |
-          ./mvnw $BUILD_OPTS
-
-  prepare_test:
-    runs-on: ubuntu-latest
-    env:
-      JOB_COUNT: 10
-    steps:
-      - uses: actions/checkout@v1
-      - name: Prepare test list
-        run: |
-          cd test
-          bash ./prepare-test.sh
-      - name: Upload test list
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs
-
-  test_result:
-    needs: [test_job_1, test_job_2, test_job_3, test_job_4, test_job_5, test_job_6, test_job_7, test_job_8, test_job_9, test_job_10]
-    if: always()
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v1
-      - name: Download test result
-        uses: actions/download-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/
-      - name: Merge test result
-        run: ./test/merge-test-results.sh
-
-  test_job_1:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-1.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_2:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-2.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_3:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-3.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_4:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-4.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_5:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-5.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_6:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-6.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_7:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-7.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_8:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-8.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_9:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-9.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
-
-  test_job_10:
-    needs: prepare_test
-    runs-on: ubuntu-latest
-    env:
-      TEST_CASE_FILE: jobs/testcases-10.txt
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v1
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-maven-
-      - name: Set up JDK 1.8
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-      - name: Build dubbo-samples and test image
-        run: |
-          cd test && bash ./build-samples-and-test-image.sh
-      - name: Download test list
-        uses: actions/download-artifact@v2
-        with:
-          name: test-list
-          path: test/jobs/
-      - name: Run tests
-        run: cd test && BUILD=n bash ./run-tests.sh
-      - name: Clean images
-        run: cd test && bash ./clean-damaged-image.sh
-      - name: Upload test result
-        if: always()
-        uses: actions/upload-artifact@v2
-        with:
-          name: test-result
-          path: test/jobs/*-result*
diff --git a/.github/workflows/nightly-dubbo-2.yml b/.github/workflows/nightly-dubbo-2.yml
new file mode 100644
index 0000000..018914c
--- /dev/null
+++ b/.github/workflows/nightly-dubbo-2.yml
@@ -0,0 +1,374 @@
+name: Nightly - Dubbo 2
+
+on:
+  schedule:
+    # nightly build at 2:00
+    - cron:  '0 2 * * *'
+  workflow_dispatch:
+    inputs:
+      remark:
+        description: 'test description'
+        required: false
+        default: 'test'
+
+
+env:
+  FORK_COUNT: 2
+  FAIL_FAST: 0
+  SHOW_ERROR_DETAIL: 1
+  BUILD_OPTS: -U --batch-mode --no-transfer-progress --settings ${{github.workspace}}/.mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
+  #multi-version size limit
+  VERSIONS_LIMIT: 12
+  CANDIDATE_VERSIONS: '
+    dubbo.version: 2.7.8, 2.7.9-SNAPSHOT;
+    spring.version: 4.1.9.RELEASE, 4.2.9.RELEASE, 5.1.20.RELEASE, 5.3.3;
+    spring-boot.version: 1.1.12.RELEASE, 1.2.8.RELEASE, 1.3.8.RELEASE, 1.4.7.RELEASE;
+    spring-boot.version: 2.0.9.RELEASE, 2.1.18.RELEASE, 2.2.12.RELEASE, 2.3.7.RELEASE
+    '
+
+jobs:
+  build-samples:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build with Maven
+        run: |
+          ./mvnw $BUILD_OPTS
+
+  build-dubbo:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          repository: 'apache/dubbo'
+          ref: master
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+      - name: Get last git commit hash
+        id: git-hash
+        run: |
+          #compare dubbo commit id
+          last_commit_id=`git log --format="%H" -n 1`
+          echo "::set-output name=commit_id::$last_commit_id"
+          if [ -f ~/.m2/repository/org/apache/dubbo/dubbo-commit-id ];then
+            cache_commit_id=`cat ~/.m2/repository/org/apache/dubbo/dubbo-commit-id`
+          fi
+          if [ "$last_commit_id" == "$cache_commit_id" ];then
+            echo "::set-output name=cache-hit::true"
+          else
+            echo "::set-output name=cache-hit::false"
+          fi
+      - name: Cache local Maven repository
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK 8
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/setup-java@v1
+        with:
+          java-version: 8
+      - name: Build dubbo
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        run: |
+          ./mvnw -U --batch-mode --no-transfer-progress  clean install -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
+      - name: Update commit id
+        run: |
+          echo commit_id: ${{steps.git-hash.outputs.commit_id}}
+          echo ${{steps.git-hash.outputs.commit_id}} > ~/.m2/repository/org/apache/dubbo/dubbo-commit-id
+
+  prepare_test:
+    runs-on: ubuntu-latest
+    env:
+      #'JOB_COUNT' MUST match needs job list of 'test_result' job
+      JOB_COUNT: 5
+    steps:
+      - uses: actions/checkout@v1
+      - name: Prepare test list
+        run: |
+          cd test
+          bash ./prepare-test.sh
+      - name: Upload test list
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs
+
+  test_result:
+    #testjob list MUST match 'JOB_COUNT' of 'prepare_test' job
+    needs: [testjob_1,testjob_2,testjob_3,testjob_4,testjob_5]
+    if: always()
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    env:
+      JAVA_VER: ${{matrix.java}}
+    steps:
+      - uses: actions/checkout@v1
+      - name: Download test result
+        uses: actions/download-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/
+      - name: Merge test result - java ${{matrix.java}}
+        run: ./test/merge-test-results.sh
+
+  testjob_1:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_2:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_3:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_4:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_5:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
diff --git a/.github/workflows/nightly-dubbo-3.yml b/.github/workflows/nightly-dubbo-3.yml
new file mode 100644
index 0000000..17ff06e
--- /dev/null
+++ b/.github/workflows/nightly-dubbo-3.yml
@@ -0,0 +1,374 @@
+name: Nightly - Dubbo 3
+
+on:
+  schedule:
+    # nightly build at 2:00
+    - cron:  '0 2 * * *'
+  workflow_dispatch:
+    inputs:
+      remark:
+        description: 'test description'
+        required: false
+        default: 'test'
+
+
+env:
+  FORK_COUNT: 2
+  FAIL_FAST: 0
+  SHOW_ERROR_DETAIL: 1
+  BUILD_OPTS: -U --batch-mode --no-transfer-progress --settings ${{github.workspace}}/.mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
+  #multi-version size limit
+  VERSIONS_LIMIT: 12
+  CANDIDATE_VERSIONS: '
+    dubbo.version: 3.0.0-SNAPSHOT;
+    spring.version: 4.1.9.RELEASE, 4.2.9.RELEASE, 5.1.20.RELEASE, 5.3.3;
+    spring-boot.version: 1.1.12.RELEASE, 1.2.8.RELEASE, 1.3.8.RELEASE, 1.4.7.RELEASE;
+    spring-boot.version: 2.0.9.RELEASE, 2.1.18.RELEASE, 2.2.12.RELEASE, 2.3.7.RELEASE;
+    '
+
+jobs:
+  build-samples:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build with Maven
+        run: |
+          ./mvnw $BUILD_OPTS
+
+  build-dubbo:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          repository: 'apache/dubbo'
+          ref: master
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+      - name: Get last git commit hash
+        id: git-hash
+        run: |
+          #compare dubbo commit id
+          last_commit_id=`git log --format="%H" -n 1`
+          echo "::set-output name=commit_id::$last_commit_id"
+          if [ -f ~/.m2/repository/org/apache/dubbo/dubbo-commit-id ];then
+            cache_commit_id=`cat ~/.m2/repository/org/apache/dubbo/dubbo-commit-id`
+          fi
+          if [ "$last_commit_id" == "$cache_commit_id" ];then
+            echo "::set-output name=cache-hit::true"
+          else
+            echo "::set-output name=cache-hit::false"
+          fi
+      - name: Cache local Maven repository
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Set up JDK 8
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        uses: actions/setup-java@v1
+        with:
+          java-version: 8
+      - name: Build dubbo
+        if: steps.git-hash.outputs.cache-hit != 'true'
+        run: |
+          ./mvnw -U --batch-mode --no-transfer-progress  clean install -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
+      - name: Update commit id
+        run: |
+          echo commit_id: ${{steps.git-hash.outputs.commit_id}}
+          echo ${{steps.git-hash.outputs.commit_id}} > ~/.m2/repository/org/apache/dubbo/dubbo-commit-id
+
+  prepare_test:
+    runs-on: ubuntu-latest
+    env:
+      #'JOB_COUNT' MUST match needs job list of 'test_result' job
+      JOB_COUNT: 5
+    steps:
+      - uses: actions/checkout@v1
+      - name: Prepare test list
+        run: |
+          cd test
+          bash ./prepare-test.sh
+      - name: Upload test list
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs
+
+  test_result:
+    #testjob list MUST match 'JOB_COUNT' of 'prepare_test' job
+    needs: [testjob_1,testjob_2,testjob_3,testjob_4,testjob_5]
+    if: always()
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    env:
+      JAVA_VER: ${{matrix.java}}
+    steps:
+      - uses: actions/checkout@v1
+      - name: Download test result
+        uses: actions/download-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/
+      - name: Merge test result - java ${{matrix.java}}
+        run: ./test/merge-test-results.sh
+
+  testjob_1:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_2:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_3:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_4:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
+
+  testjob_5:
+    needs: [prepare_test, build-dubbo]
+    runs-on: ubuntu-latest
+    env:
+      JAVA_VER: ${{matrix.java}}
+      TEST_CASE_FILE: jobs/${{github.job}}.txt
+    strategy:
+      fail-fast: false
+      matrix:
+        java: [8, 11]
+    steps:
+      - uses: actions/checkout@v1
+      - name: Cache local Maven repository
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
+      - name: Dubbo cache
+        uses: actions/cache@v2
+        with:
+          path: ~/.m2/repository/org/apache/dubbo
+          key: ${{ runner.os }}-dubbo-snapshot
+          restore-keys: |
+            ${{ runner.os }}-dubbo-
+      - name: Download test list
+        uses: actions/download-artifact@v2
+        with:
+          name: test-list
+          path: test/jobs/
+      - name: Set up JDK ${{matrix.java}}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{matrix.java}}
+      - name: Build test image
+        run: |
+          cd test && bash ./build-test-image.sh
+      - name: Run tests
+        run: cd test && bash ./run-tests.sh
+      - name: Upload test result
+        if: always()
+        uses: actions/upload-artifact@v2
+        with:
+          name: test-result
+          path: test/jobs/*-result*
diff --git a/.gitignore b/.gitignore
index 293c737..2d0286b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,4 +55,4 @@ logs/
 coverage.txt
 
 test/jobs
-testcases*.txt
\ No newline at end of file
+version-matrix.txt
\ No newline at end of file
diff --git a/README.md b/README.md
index 527567e..f0c1768 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 Samples for Apache Dubbo
 
-![Build Status](https://github.com/apache/dubbo-samples/workflows/Java%20CI/badge.svg)
+![Build Status](https://github.com/apache/dubbo-samples/workflows/Dubbo%202/badge.svg)
 ![license](https://img.shields.io/github/license/apache/dubbo-samples.svg)
 
 This repository contains a number of projects to illustrate various usages of Dubbo from basic to advanced, pls. check README in each individual sub projects. It is also helpful to cross reference to [Dubbo User Manual](http://dubbo.apache.org/en-us/docs/user/quick-start.html) to understand the features demoed in this project.
@@ -63,7 +63,7 @@ Then we use the `run-tests.sh` script to run the test cases.
 
   ```bash
   cd dubbo-samples/test
-  BUILD=all ./run-tests.sh 
+  ./run-tests.sh 
   ```
 
 If docker container fails to startup successfully in any case, you can check log files in directory `${project.basedir}/target/logs` to understand what happens.
@@ -77,9 +77,16 @@ If you are interested in contributing more integration test for dubbo, pls. read
 
 Please follow the steps below:
 
-1. Add a file named `case-configuration.yml` to integration test project.
+1. Add a file named `case-configuration.yml` to test project.
 
-2. Configure test environment:
+   This file is used to configure the test modules and environment, including dubbo provider / test services, 
+   dependent third-party services.
+
+2. Add a file named `case-versions.conf` to test project.
+
+   This file is used to configure the supported component version rules to support multi-version testing.
+
+**Details of `case-configuration.yml`:**
 
 Take the case `dubbo-samples-annotation` as an example:
 
@@ -140,6 +147,33 @@ props:
 Another template is `app-external-zookeeper.yml`, which supports an external zookeeper service.
 you can find all the templates in the directory `test/dubbo-scenario-builder/src/main/resources/configs`.
 
+**Details of `case-versions.conf`:**
+
+Version rules for spring app:
+
+```
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
+```
+
+Version rules for spring-boot 1.x app:
+
+```
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=1.*
+```
+
+Version rules for spring-boot 2.x app:
+
+```
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=2.*
+```
+
+
 For more details, please refer to the following case configurations:
 
  * [dubbo-samples-annotation](dubbo-samples-annotation/case-configuration.yml) : A simple provider service with builtin zookeeper.
diff --git a/dubbo-samples-annotation/case-versions.conf b/dubbo-samples-annotation/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-annotation/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-api/case-versions.conf b/dubbo-samples-api/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-api/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-async/dubbo-samples-async-generated-future/case-versions.conf b/dubbo-samples-async/dubbo-samples-async-generated-future/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-generated-future/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-async/dubbo-samples-async-onerror/case-versions.conf b/dubbo-samples-async/dubbo-samples-async-onerror/case-versions.conf
new file mode 100644
index 0000000..7489fe9
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-onerror/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring-boot.version=1.*
diff --git a/dubbo-samples-async/dubbo-samples-async-original-future/case-versions.conf b/dubbo-samples-async/dubbo-samples-async-original-future/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-original-future/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-async/dubbo-samples-async-provider/case-versions.conf b/dubbo-samples-async/dubbo-samples-async-provider/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-provider/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-async/dubbo-samples-async-simple/case-versions.conf b/dubbo-samples-async/dubbo-samples-async-simple/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-simple/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-attachment/case-versions.conf b/dubbo-samples-attachment/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-attachment/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-basic/case-versions.conf b/dubbo-samples-basic/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-basic/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-cache/case-versions.conf b/dubbo-samples-cache/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-cache/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-callback/case-versions.conf b/dubbo-samples-callback/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-callback/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-chain/case-versions.conf b/dubbo-samples-chain/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-chain/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-compatible/case-versions.conf b/dubbo-samples-compatible/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-compatible/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-annotation/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-annotation/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-annotation/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-api/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-api/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-api/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-externalconfiguration/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-externalconfiguration/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-externalconfiguration/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-multi-registries/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-multi-registries/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-multi-registries/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/case-versions.conf b/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-consul/case-versions.conf b/dubbo-samples-consul/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-consul/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-context/case-versions.conf b/dubbo-samples-context/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-context/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-default-config/case-versions.conf b/dubbo-samples-default-config/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-default-config/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-direct/case-versions.conf b/dubbo-samples-direct/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-direct/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-docker/case-versions.conf b/dubbo-samples-docker/case-versions.conf
new file mode 100644
index 0000000..f2fe52c
--- /dev/null
+++ b/dubbo-samples-docker/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=1.*
diff --git a/dubbo-samples-docker/pom.xml b/dubbo-samples-docker/pom.xml
index 3a6b22d..3ef54ca 100644
--- a/dubbo-samples-docker/pom.xml
+++ b/dubbo-samples-docker/pom.xml
@@ -29,7 +29,7 @@
         <source.level>1.8</source.level>
         <target.level>1.8</target.level>
         <dubbo.version>2.7.7</dubbo.version>
-        <spring.boot.version>1.5.21.RELEASE</spring.boot.version>
+        <spring-boot.version>1.5.21.RELEASE</spring-boot.version>
         <junit.version>4.12</junit.version>
         <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
     </properties>
@@ -40,7 +40,7 @@
                 <!-- Import dependency management from Spring Boot -->
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-dependencies</artifactId>
-                <version>${spring.boot.version}</version>
+                <version>${spring-boot.version}</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
diff --git a/dubbo-samples-echo/case-versions.conf b/dubbo-samples-echo/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-echo/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-generic/dubbo-samples-generic-call/case-versions.conf b/dubbo-samples-generic/dubbo-samples-generic-call/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-generic/dubbo-samples-generic-call/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-generic/dubbo-samples-generic-impl/case-versions.conf b/dubbo-samples-generic/dubbo-samples-generic-impl/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-generic/dubbo-samples-generic-impl/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-generic/dubbo-samples-generic-impl/pom.xml b/dubbo-samples-generic/dubbo-samples-generic-impl/pom.xml
index 87f04aa..c297f70 100644
--- a/dubbo-samples-generic/dubbo-samples-generic-impl/pom.xml
+++ b/dubbo-samples-generic/dubbo-samples-generic-impl/pom.xml
@@ -89,4 +89,21 @@
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <!-- For jdk 11 above JavaEE annotation -->
+        <profile>
+            <id>javax.annotation</id>
+            <activation>
+                <jdk>[1.11,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>javax.annotation</groupId>
+                    <artifactId>javax.annotation-api</artifactId>
+                    <version>1.3.2</version>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
 </project>
diff --git a/dubbo-samples-generic/dubbo-samples-generic-type/case-versions.conf b/dubbo-samples-generic/dubbo-samples-generic-type/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-generic/dubbo-samples-generic-type/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-governance/dubbo-samples-applevel-override/case-versions.conf b/dubbo-samples-governance/dubbo-samples-applevel-override/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-governance/dubbo-samples-applevel-override/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-governance/dubbo-samples-configconditionrouter/case-versions.conf b/dubbo-samples-governance/dubbo-samples-configconditionrouter/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-governance/dubbo-samples-configconditionrouter/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-governance/dubbo-samples-servicelevel-override/case-versions.conf b/dubbo-samples-governance/dubbo-samples-servicelevel-override/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-governance/dubbo-samples-servicelevel-override/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-governance/dubbo-samples-tagrouter/case-versions.conf b/dubbo-samples-governance/dubbo-samples-tagrouter/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-governance/dubbo-samples-tagrouter/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-group/case-versions.conf b/dubbo-samples-group/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-group/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-grpc/dubbo-samples-original/case-versions.conf b/dubbo-samples-grpc/dubbo-samples-original/case-versions.conf
new file mode 100644
index 0000000..f2fe52c
--- /dev/null
+++ b/dubbo-samples-grpc/dubbo-samples-original/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=1.*
diff --git a/dubbo-samples-grpc/dubbo-samples-original/pom.xml b/dubbo-samples-grpc/dubbo-samples-original/pom.xml
index 83bf319..542e891 100644
--- a/dubbo-samples-grpc/dubbo-samples-original/pom.xml
+++ b/dubbo-samples-grpc/dubbo-samples-original/pom.xml
@@ -48,6 +48,16 @@
             <groupId>io.grpc</groupId>
             <artifactId>grpc-netty</artifactId>
             <version>${grpc.version}</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>netty-codec-http2</artifactId>
+                    <groupId>io.netty</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>netty-handler-proxy</artifactId>
+                    <groupId>io.netty</groupId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>io.grpc</groupId>
diff --git a/dubbo-samples-local/case-versions.conf b/dubbo-samples-local/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-local/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-merge/case-versions.conf b/dubbo-samples-merge/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-merge/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/case-versions.conf b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotation/case-versions.conf b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotation/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotation/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/case-versions.conf b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/case-versions.conf b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-metrics/case-versions.conf b/dubbo-samples-metrics/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-metrics/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-mock/case-versions.conf b/dubbo-samples-mock/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-mock/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-monitor/case-versions.conf b/dubbo-samples-monitor/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-monitor/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-multi-registry/case-versions.conf b/dubbo-samples-multi-registry/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-multi-registry/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-nacos/dubbo-samples-nacos-conditionrouter/case-versions.conf b/dubbo-samples-nacos/dubbo-samples-nacos-conditionrouter/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-nacos/dubbo-samples-nacos-conditionrouter/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-nacos/dubbo-samples-nacos-configcenter/case-versions.conf b/dubbo-samples-nacos/dubbo-samples-nacos-configcenter/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-nacos/dubbo-samples-nacos-configcenter/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-nacos/dubbo-samples-nacos-override/case-versions.conf b/dubbo-samples-nacos/dubbo-samples-nacos-override/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-nacos/dubbo-samples-nacos-override/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-nacos/dubbo-samples-nacos-registry/case-versions.conf b/dubbo-samples-nacos/dubbo-samples-nacos-registry/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-nacos/dubbo-samples-nacos-registry/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-nacos/dubbo-samples-nacos-tagrouter/case-versions.conf b/dubbo-samples-nacos/dubbo-samples-nacos-tagrouter/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-nacos/dubbo-samples-nacos-tagrouter/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-notify/case-versions.conf b/dubbo-samples-notify/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-notify/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-protostuff/case-versions.conf b/dubbo-samples-protostuff/case-versions.conf
new file mode 100644
index 0000000..6a96cc8
--- /dev/null
+++ b/dubbo-samples-protostuff/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=2.*
diff --git a/dubbo-samples-rest/case-versions.conf b/dubbo-samples-rest/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-rest/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-sentinel/case-versions.conf b/dubbo-samples-sentinel/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-sentinel/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-serialization/dubbo-samples-serialization-java/case-versions.conf b/dubbo-samples-serialization/dubbo-samples-serialization-java/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-serialization/dubbo-samples-serialization-java/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation/case-versions.conf b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple/case-versions.conf b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/case-versions.conf b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml/case-versions.conf b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-spi-compatible/case-versions.conf b/dubbo-samples-spi-compatible/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-spi-compatible/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-spring-boot-hystrix/case-versions.conf b/dubbo-samples-spring-boot-hystrix/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-spring-boot-hystrix/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-spring-hystrix/case-versions.conf b/dubbo-samples-spring-hystrix/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-spring-hystrix/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-stub/case-versions.conf b/dubbo-samples-stub/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-stub/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-switch-serialization-thread/case-versions.conf b/dubbo-samples-switch-serialization-thread/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-switch-serialization-thread/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-thrift/case-versions.conf b/dubbo-samples-thrift/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-thrift/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-transaction/case-versions.conf b/dubbo-samples-transaction/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-transaction/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-validation/case-versions.conf b/dubbo-samples-validation/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-validation/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-version/case-versions.conf b/dubbo-samples-version/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-version/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-zipkin/case-versions.conf b/dubbo-samples-zipkin/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-zipkin/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/dubbo-samples-zookeeper/case-versions.conf b/dubbo-samples-zookeeper/case-versions.conf
new file mode 100644
index 0000000..978f7e7
--- /dev/null
+++ b/dubbo-samples-zookeeper/case-versions.conf
@@ -0,0 +1,6 @@
+
+# Supported component versions of the test case
+
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
diff --git a/test/README.md b/test/README.md
index 666e5e2..98c8370 100644
--- a/test/README.md
+++ b/test/README.md
@@ -55,7 +55,7 @@ Run all tests:
 
 ```
 cd dubbo-samples/test
-BUILD=all ./run-tests.sh
+./run-tests.sh
 ```
 
 ### Builtin parent configuration
diff --git a/test/build-samples-and-test-image.sh b/test/build-samples-and-test-image.sh
deleted file mode 100755
index 0fc81ee..0000000
--- a/test/build-samples-and-test-image.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/bash
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-test_image_log=$DIR/test-image.log
-samples_log=$DIR/samples.log
-
-export DIR=$DIR
-export test_image_log=$test_image_log
-export samples_log=$samples_log
-
-cd $DIR
-echo "Build test image .."
-bash ./build-test-image.sh &> $test_image_log &
-build_image_pid=$!
-
-echo "Build samples .."
-BUILD_OPTS="-U --batch-mode --no-transfer-progress --settings .mvn/settings.xml"
-BUILD_OPTS="$BUILD_OPTS clean package dependency:copy-dependencies -DskipTests"
-cd $DIR/..
-./mvnw $BUILD_OPTS &> $samples_log &
-build_samples_pid=$!
-
-echo "-------------------------------------------------------------------"
-echo "Waiting test image building: $build_image_pid .."
-tail -n 1000 -f $test_image_log &
-wait $build_image_pid
-result=$?
-if [ $result -ne 0 ];then
-  echo "Build test image failed"
-  exit $result
-fi
-
-echo ""
-echo "-------------------------------------------------------------------"
-echo "Waiting samples building: $build_samples_pid .."
-tail -n 500 -f $samples_log &
-wait $build_samples_pid
-result=$?
-if [ $result -ne 0 ];then
-  echo "Build dubbo-samples with maven failed"
-  exit $result
-fi
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
index 0a6d760..3801345 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
@@ -26,12 +26,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
 
-import java.io.DataInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -70,16 +67,18 @@ public class ConfigurationImpl implements IConfiguration {
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigurationImpl.class);
     private final CaseConfiguration configuration;
+    private boolean isJdk9OrLater;
     private String scenarioHome;
     private String configBasedir;
     private String scenarioName;
     private final String scenarioLogDir;
-    private int scenarioTimeout = 90;
+    private int scenarioTimeout = 120;
     private int javaDebugPort = 20660;
     private int debugTimeout = 36000;
     private Set<Pattern> debugPatterns = new HashSet<>();
     private Set<String> debugServices = new HashSet<>();
     private Set<String> healthcheckServices = new HashSet<>();
+    private String testImageVersion;
 
     public ConfigurationImpl() throws IOException, ConfigureFileNotFoundException {
         String configureFile = System.getProperty("configure.file");
@@ -102,6 +101,11 @@ public class ConfigurationImpl implements IConfiguration {
             scenarioName = new File(configBasedir).getName();
         }
 
+        testImageVersion = System.getProperty("test.image.version", "8");
+        String verstr = StringUtils.substringBefore(testImageVersion, ".");
+        int majorVersion = Integer.parseInt(verstr);
+        isJdk9OrLater = (majorVersion > 8);
+
         String debugService = System.getProperty("debug.service");
         if (StringUtils.isNotBlank(debugService)) {
             String[] strs = debugService.split(",");
@@ -128,8 +132,8 @@ public class ConfigurationImpl implements IConfiguration {
             scenarioTimeout = debugTimeout;
         }
 
-        logger.info("scenarioName:{}, timeout: {}, debugServices:{}, config: {}",
-                scenarioName, scenarioTimeout, debugServices, configuration);
+        logger.info("scenarioName:{}, timeout: {}, testImageVersion: {}, debugServices:{}, config: {}",
+                scenarioName, scenarioTimeout, testImageVersion, debugServices, configuration);
 
     }
 
@@ -149,7 +153,7 @@ public class ConfigurationImpl implements IConfiguration {
 
     private CaseConfiguration loadCaseConfiguration(String configureFile) throws IOException {
         // read 'props'
-        String configYaml = readFully(configureFile);
+        String configYaml = FileUtil.readFully(configureFile);
         CaseConfiguration tmpConfiguration = parseConfiguration(configYaml);
         Map<String, String> props = tmpConfiguration.getProps();
         if (props == null) {
@@ -219,7 +223,7 @@ public class ConfigurationImpl implements IConfiguration {
         try {
             String file = "configs/" + caseConfiguration.getFrom();
             InputStream inputStream = CaseConfiguration.class.getClassLoader().getResourceAsStream(file);
-            return readFully(inputStream);
+            return FileUtil.readFully(inputStream);
         } catch (Exception e) {
             logger.error("load parent config failed: " + caseConfiguration.getFrom(), e);
             throw new IOException("load parent config failed: " + caseConfiguration.getFrom(), e);
@@ -237,7 +241,7 @@ public class ConfigurationImpl implements IConfiguration {
             ServiceComponent service = entry.getValue();
             String type = service.getType();
             if (isAppOrTestService(type)) {
-                service.setImage(SAMPLE_TEST_IMAGE);
+                service.setImage(SAMPLE_TEST_IMAGE+":"+testImageVersion);
                 service.setBasedir(toAbsolutePath(service.getBasedir()));
                 if (service.getVolumes() == null) {
                     service.setVolumes(new ArrayList<>());
@@ -274,7 +278,12 @@ public class ConfigurationImpl implements IConfiguration {
                         //set java remote debug opts
                         //-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
                         int debugPort = nextDebugPort();
-                        String debugOpts = String.format("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=%s", debugPort);
+                        String debugOpts;
+                        if (isJdk9OrLater) {
+                            debugOpts = String.format("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:%s", debugPort);
+                        }else {
+                            debugOpts = String.format("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=%s", debugPort);
+                        }
                         appendEnv(service, ENV_DEBUG_OPTS, debugOpts);
 
                         //mapping debug port
@@ -452,19 +461,6 @@ public class ConfigurationImpl implements IConfiguration {
         throw new RuntimeException("Illegal service type: " + type);
     }
 
-    private String readFully(String file) throws IOException {
-        try (FileInputStream fis = new FileInputStream(file)) {
-            return readFully(fis);
-        }
-    }
-
-    private String readFully(InputStream input) throws IOException {
-        DataInputStream dis = new DataInputStream(input);
-        byte[] bytes = new byte[input.available()];
-        dis.readFully(bytes);
-        return new String(bytes, StandardCharsets.UTF_8);
-    }
-
     private Pattern pattern = Pattern.compile("\\$\\{(.+?)}");
 
     private String replaceHolders(String str, Map<String, String> props) {
@@ -500,18 +496,18 @@ public class ConfigurationImpl implements IConfiguration {
     }
 
     @Override
-    public String dockerImageVersion() {
-        return System.getProperty("docker.image.version", "latest");
+    public String testImageVersion() {
+        return testImageVersion;
     }
 
     @Override
     public String dockerNetworkName() {
-        return (scenarioName() + "-" + dockerImageVersion()).toLowerCase();
+        return (scenarioName() + "-" + testImageVersion()).toLowerCase();
     }
 
     @Override
     public String dockerContainerName() {
-        return (scenarioName() + "-" + scenarioVersion() + "-" + dockerImageVersion()).toLowerCase();
+        return (scenarioName() + "-" + scenarioVersion() + "-" + testImageVersion()).toLowerCase();
     }
 
     @Override
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/FileUtil.java
similarity index 56%
copy from test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
copy to test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/FileUtil.java
index 6b19381..d24d3dc 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/FileUtil.java
@@ -17,35 +17,23 @@
 
 package org.apache.dubbo.scenario.builder;
 
-
-import org.apache.dubbo.scenario.builder.vo.CaseConfiguration;
-
-import java.util.Map;
-
-public interface IConfiguration {
-
-    ScenarioRunningScriptGenerator scenarioGenerator();
-
-    CaseConfiguration caseConfiguration();
-
-    String scenarioName();
-
-    String scenarioVersion();
-
-    String dockerContainerName();
-
-    String dockerNetworkName();
-
-    String dockerImageVersion();
-
-    String scenarioHome();
-
-    String outputDir();
-
-    String jacocoHome();
-
-    String debugMode();
-
-    Map<String, Object> toMap();
-
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+public class FileUtil {
+    public static String readFully(String file) throws IOException {
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return readFully(fis);
+        }
+    }
+
+    public static String readFully(InputStream input) throws IOException {
+        DataInputStream dis = new DataInputStream(input);
+        byte[] bytes = new byte[input.available()];
+        dis.readFully(bytes);
+        return new String(bytes, StandardCharsets.UTF_8);
+    }
 }
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
index 6b19381..abebb5d 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
@@ -36,7 +36,7 @@ public interface IConfiguration {
 
     String dockerNetworkName();
 
-    String dockerImageVersion();
+    String testImageVersion();
 
     String scenarioHome();
 
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java
new file mode 100644
index 0000000..e413753
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.scenario.builder;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * Multi-version matcher
+ */
+public class VersionMatcher {
+
+    private static final Logger logger = LoggerFactory.getLogger(VersionMatcher.class);
+    public static final String CASE_VERSIONS_FILE = "caseVersionsFile";
+    public static final String CANDIDATE_VERSIONS = "candidateVersions";
+    public static final String OUTPUT_FILE = "outputFile";
+    public static final String VERSIONS_LIMIT = "versionsLimit";
+    public static final String INCLUDE_CASE_SPECIFIC_VERSION = "includeCaseSpecificVersion";
+
+    public static void main(String[] args) throws Exception {
+
+        String caseVersionsFile = System.getProperty(CASE_VERSIONS_FILE);
+        String candidateVersionListStr = System.getProperty(CANDIDATE_VERSIONS);
+        String outputFile = System.getProperty(OUTPUT_FILE);
+        int limit = Integer.parseInt(System.getProperty(VERSIONS_LIMIT, "4"));
+        // whether include specific version which defined in case-versions.conf
+        // specific version: a real version not contains wildcard '*'
+        boolean includeCaseSpecificVersion = Boolean.parseBoolean(System.getProperty(INCLUDE_CASE_SPECIFIC_VERSION, "true"));
+
+        if (StringUtils.isBlank(candidateVersionListStr)) {
+            logger.error("Missing system prop: '{}'", CANDIDATE_VERSIONS);
+            System.exit(1);
+        }
+        if (StringUtils.isBlank(caseVersionsFile)) {
+            logger.error("Missing system prop: '{}'", CASE_VERSIONS_FILE);
+            System.exit(1);
+        }
+        File file = new File(caseVersionsFile);
+        if (!file.exists() || !file.isFile()) {
+            logger.error("file not exists or isn't a file: {}", file.getAbsolutePath());
+            System.exit(1);
+        }
+        if (StringUtils.isBlank(outputFile)) {
+            logger.error("Missing system prop: '{}'", OUTPUT_FILE);
+            System.exit(1);
+        }
+        new File(outputFile).getParentFile().mkdirs();
+
+        logger.info("{}: {}", CANDIDATE_VERSIONS, candidateVersionListStr);
+        logger.info("{}: {}", CASE_VERSIONS_FILE, caseVersionsFile);
+        logger.info("{}: {}", OUTPUT_FILE, outputFile);
+
+        // parse and expand to versions list
+        List<String> candidateVersionList = parseVersionList(candidateVersionListStr);
+
+        // parse case version rules
+        Map<String, List<String>> caseVersionRules = parseCaseVersionRules(caseVersionsFile);
+
+        Map<String, List<String>> matchVersions = new LinkedHashMap<>();
+        caseVersionRules.forEach((component, versionPatterns) -> {
+            for (String versionPattern : versionPatterns) {
+                // convert 'component:version_prefix*' to regex
+                String regex = "\\Q" + component + ":" + versionPattern.replace("*", "\\E.*?\\Q") + "\\E";
+                Pattern pattern = Pattern.compile(regex);
+                boolean matched = false;
+                for (String version : candidateVersionList) {
+                    if (pattern.matcher(version).matches()) {
+                        getMatchVersionList(matchVersions, component).add(version);
+                        matched = true;
+                    }
+                }
+                //add case specific version
+                if (!matched && includeCaseSpecificVersion && !versionPattern.contains("*")) {
+                    getMatchVersionList(matchVersions, component).add(component+":"+versionPattern);
+                }
+            }
+        });
+
+        if (caseVersionRules.size() != matchVersions.size()) {
+            List<String> components = new ArrayList<>(caseVersionRules.keySet());
+            components.removeAll(matchVersions.keySet());
+            for (String component : components) {
+                logger.error("Component not match, component: {}, rules: {}, candidateVersionList: {}", component, caseVersionRules.get(component), candidateVersionListStr);
+            }
+            System.exit(2);
+        }
+
+        List<List<String>> versionProfiles = new ArrayList<>();
+        for (Map.Entry<String, List<String>> entry : matchVersions.entrySet()) {
+            String component = entry.getKey();
+            List<String> versions = entry.getValue();
+            versionProfiles = appendComponent(versionProfiles, component, versions);
+        }
+
+        if (versionProfiles.isEmpty()) {
+            logger.error("");
+            System.exit(2);
+        }
+        if (versionProfiles.size() > limit) {
+            logger.warn("Version matrix size exceeds limit and will be truncated, total: {}, limit: {}", versionProfiles.size(), limit);
+        }
+        try (FileOutputStream fos = new FileOutputStream(outputFile);
+             PrintWriter pw = new PrintWriter(fos)) {
+            StringBuilder sb = new StringBuilder();
+            int size = Math.min(versionProfiles.size(), limit);
+            for (int i = 0; i < size; i++) {
+                List<String> profile = versionProfiles.get(i);
+                for (String s : profile) {
+                    sb.append("-D").append(s).append(" ");
+                }
+                sb.append("\n");
+            }
+            pw.print(sb);
+            logger.info("Version matrix: \n{}", sb);
+        } catch (IOException e) {
+            logger.error("Write version matrix failed: " + e.toString(), e);
+        }
+
+    }
+
+    private static List<String> getMatchVersionList(Map<String, List<String>> matchVersions, String component) {
+        return matchVersions.computeIfAbsent(component, (key) -> new ArrayList<>());
+    }
+
+    private static List<List<String>> appendComponent(List<List<String>> versionProfiles, String component, List<String> versions) {
+        List<List<String>> newProfiles = new ArrayList<>();
+        for (String version : versions) {
+            if (versionProfiles.isEmpty()) {
+                List<String> newProfile = new ArrayList<>();
+                newProfile.add(version);
+                newProfiles.add(newProfile);
+            } else {
+                //extends version matrix
+                for (int i = 0; i < versionProfiles.size(); i++) {
+                    List<String> profile = versionProfiles.get(i);
+                    List<String> newProfile = new ArrayList<>(profile);
+                    newProfile.add(version);
+                    newProfiles.add(newProfile);
+                }
+            }
+        }
+        return newProfiles;
+    }
+
+    private static Map<String, List<String>> parseCaseVersionRules(String caseVersionsFile) throws Exception {
+        //dubbo.version=2.7*, 3.*
+        //spring.version=4.*, 5.*
+        try {
+            Map<String, List<String>> ruleMap = new LinkedHashMap<>();
+            String content = FileUtil.readFully(caseVersionsFile);
+            BufferedReader br = new BufferedReader(new StringReader(content));
+            String line;
+            while ((line = br.readLine()) != null) {
+                line = line.trim();
+                if (line.startsWith("#") || StringUtils.isBlank(line)) {
+                    continue;
+                }
+                String[] strs = line.split("=");
+                String component = strs[0].trim();
+                String patternStr = strs[1];
+                String[] patterns = patternStr.split(",");
+                List<String> patternList = new ArrayList<>();
+                for (String pattern : patterns) {
+                    patternList.add(pattern.trim());
+                }
+                ruleMap.put(component, patternList);
+            }
+            return ruleMap;
+        } catch (Exception e) {
+            logger.error("Parse case versions rules failed: {}", caseVersionsFile, e);
+            throw e;
+        }
+    }
+
+    private static List<String> parseVersionList(String versionListStr) {
+        // "<component1>:<version1>[,version2];<component2>:<version1>[,version2]"
+        // "<component1>:<version1>[;component1:<version2];<component2>:<version1>[;component2:version2];"
+
+        List<String> versionList = new ArrayList<>();
+        //split components by ';' or '\n'
+        String[] compvers = versionListStr.split("[;\n]");
+        for (String compver : compvers) {
+            if (StringUtils.isBlank(compver)) {
+                continue;
+            }
+            String[] strs = compver.split(":");
+            String component = strs[0].trim();
+            String[] vers = strs[1].split(",");
+            for (String ver : vers) {
+                versionList.add(component + ":" + ver.trim());
+            }
+        }
+        return versionList;
+    }
+}
diff --git a/test/dubbo-scenario-builder/src/main/resources/logback.xml b/test/dubbo-scenario-builder/src/main/resources/logback.xml
index d0fd9aa..2b2cd90 100644
--- a/test/dubbo-scenario-builder/src/main/resources/logback.xml
+++ b/test/dubbo-scenario-builder/src/main/resources/logback.xml
@@ -25,23 +25,23 @@
         </encoder>
     </appender>
 
-    <appender name="file"
-              class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <File>test.log</File>
-        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-            <FileNamePattern>test-%d{yyyy-MM-dd}.%i.log
-            </FileNamePattern>
-            <MaxHistory>10</MaxHistory>
-            <TimeBasedFileNamingAndTriggeringPolicy
-                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
-                <MaxFileSize>5MB</MaxFileSize>
-            </TimeBasedFileNamingAndTriggeringPolicy>
-        </rollingPolicy>
-        <layout class="ch.qos.logback.classic.PatternLayout">
-            <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n
-            </pattern>
-        </layout>
-    </appender>
+<!--    <appender name="file"-->
+<!--              class="ch.qos.logback.core.rolling.RollingFileAppender">-->
+<!--        <File>test.log</File>-->
+<!--        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">-->
+<!--            <FileNamePattern>test-%d{yyyy-MM-dd}.%i.log-->
+<!--            </FileNamePattern>-->
+<!--            <MaxHistory>10</MaxHistory>-->
+<!--            <TimeBasedFileNamingAndTriggeringPolicy-->
+<!--                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">-->
+<!--                <MaxFileSize>5MB</MaxFileSize>-->
+<!--            </TimeBasedFileNamingAndTriggeringPolicy>-->
+<!--        </rollingPolicy>-->
+<!--        <layout class="ch.qos.logback.classic.PatternLayout">-->
+<!--            <pattern>[%-5level] %d{HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n-->
+<!--            </pattern>-->
+<!--        </layout>-->
+<!--    </appender>-->
 
     <root level="info">
         <!-- <appender-ref ref="file" /> -->
diff --git a/test/dubbo-scenario-builder/src/main/resources/scenario.sh b/test/dubbo-scenario-builder/src/main/resources/scenario.sh
index 5a29687..b09f98e 100644
--- a/test/dubbo-scenario-builder/src/main/resources/scenario.sh
+++ b/test/dubbo-scenario-builder/src/main/resources/scenario.sh
@@ -176,7 +176,7 @@ sleep 5
 
     echo "[$scenario_name] Stopping containers .." | tee -a $scenario_log
     docker-compose -p ${project_name} -f ${compose_file} kill 2>&1 | tee -a $scenario_log > /dev/null
-
+    docker wait ${container_name} > /dev/null
 #fi
 
 if [[ $status == 0 ]];then
diff --git a/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java b/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java
new file mode 100644
index 0000000..b8f7483
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.scenario.builder;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+
+import static org.apache.dubbo.scenario.builder.VersionMatcher.CASE_VERSIONS_FILE;
+import static org.apache.dubbo.scenario.builder.VersionMatcher.OUTPUT_FILE;
+import static org.apache.dubbo.scenario.builder.VersionMatcher.CANDIDATE_VERSIONS;
+
+public class VersionMatcherTest {
+
+    @Test
+    public void testVersionMatch1() throws Exception {
+        String caseVersionRules = "# Spring app\n" +
+                "dubbo.version=2.7*, 3.*\n" +
+                "spring.version= 4.*, 5.*\n\n\n";
+
+        String candidateVersions = "dubbo.version: 2.7.7,3.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE, 5.3.2;";
+        candidateVersions += "spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 -Dspring.version:4.1.13.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 -Dspring.version:4.1.13.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 -Dspring.version:5.3.2"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 -Dspring.version:5.3.2"));
+    }
+
+    @Test
+    public void testVersionMatch2() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version=2.7*, 3.*\n" +
+                "spring-boot.version=2.*\n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.7,3.0\n";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2\n\n";
+        candidateVersions += "spring-boot.version:1.5.13.RELEASE\n";
+        candidateVersions += "spring-boot.version:2.1.1.RELEASE";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 -Dspring-boot.version:2.1.1.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 -Dspring-boot.version:2.1.1.RELEASE"));
+    }
+
+    @Test
+    public void testVersionMatchIncludeSpecificVersion() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version=2.7*, 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.7,3.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += "spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 -Dspring-boot.version:2.0.8.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 -Dspring-boot.version:2.0.8.RELEASE"));
+    }
+
+    private String getVersionMatrix(String caseVersionRules, String candidateVersions) throws Exception {
+        File caseVersionsFile = File.createTempFile("case-versions", ".conf");
+        File outputFile = File.createTempFile("case-version-matrix", ".txt");
+        caseVersionsFile.deleteOnExit();
+        outputFile.deleteOnExit();
+
+        writeToFile(caseVersionRules, caseVersionsFile);
+
+        System.setProperty(CANDIDATE_VERSIONS, candidateVersions);
+        System.setProperty(CASE_VERSIONS_FILE, caseVersionsFile.getAbsolutePath());
+        System.setProperty(OUTPUT_FILE, outputFile.getAbsolutePath());
+
+        VersionMatcher.main(new String[0]);
+
+        return FileUtil.readFully(outputFile.getAbsolutePath());
+    }
+
+    private void writeToFile(String content, File file) throws Exception {
+        try (FileOutputStream fos = new FileOutputStream(file);
+             DataOutputStream dos = new DataOutputStream(fos)) {
+            dos.writeBytes(content);
+        }
+    }
+
+}
diff --git a/test/dubbo-test-runner/build.sh b/test/dubbo-test-runner/build.sh
index a1ed26e..5ee631f 100755
--- a/test/dubbo-test-runner/build.sh
+++ b/test/dubbo-test-runner/build.sh
@@ -2,9 +2,12 @@
 
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
+JAVA_VER=${JAVA_VER:-8}
+
 DOCKER_DIR=$DIR/target/docker
 
 echo "Building dubbo-test-runner .."
+echo "Java version: $JAVA_VER"
 cd $DIR
 mvn clean package -DskipTests
 result=$?
@@ -18,4 +21,4 @@ cp -r $DIR/src/docker/* $DOCKER_DIR/
 cp $DIR/target/dubbo-test-runner-*-jar-with-dependencies.jar $DOCKER_DIR/dubbo-test-runner.jar
 
 cd $DOCKER_DIR
-docker build -t dubbo/sample-test . --build-arg DEBIAN_MIRROR=$DEBIAN_MIRROR
+docker build -t dubbo/sample-test:$JAVA_VER . --build-arg DEBIAN_MIRROR=$DEBIAN_MIRROR  --build-arg JAVA_VER=$JAVA_VER
diff --git a/test/dubbo-test-runner/src/docker/Dockerfile b/test/dubbo-test-runner/src/docker/Dockerfile
index 88f677a..c99668a 100644
--- a/test/dubbo-test-runner/src/docker/Dockerfile
+++ b/test/dubbo-test-runner/src/docker/Dockerfile
@@ -13,7 +13,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-FROM openjdk:8
+ARG JAVA_VER=8
+FROM openjdk:$JAVA_VER
 
 ARG DEBIAN_MIRROR
 RUN if [ -n "$DEBIAN_MIRROR" ]; then \
diff --git a/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/ClassLoaderUtils.java b/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/ClassLoaderUtils.java
new file mode 100644
index 0000000..74c11dd
--- /dev/null
+++ b/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/ClassLoaderUtils.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.test.runner;
+
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+
+/*
+ * from https://gist.github.com/hengyunabc/644f8e84908b7b405c532a51d8e34ba9
+ */
+public class ClassLoaderUtils {
+    @SuppressWarnings({ "restriction", "unchecked" })
+    public static URL[] getUrls(ClassLoader classLoader) {
+        if (classLoader instanceof URLClassLoader) {
+            return ((URLClassLoader) classLoader).getURLs();
+        }
+
+        // jdk9
+        if (classLoader.getClass().getName().startsWith("jdk.internal.loader.ClassLoaders$")) {
+            try {
+                Field field = Unsafe.class.getDeclaredField("theUnsafe");
+                field.setAccessible(true);
+                Unsafe unsafe = (Unsafe) field.get(null);
+
+                // jdk.internal.loader.ClassLoaders.AppClassLoader.ucp
+                Field ucpField = classLoader.getClass().getDeclaredField("ucp");
+                long ucpFieldOffset = unsafe.objectFieldOffset(ucpField);
+                Object ucpObject = unsafe.getObject(classLoader, ucpFieldOffset);
+
+                // jdk.internal.loader.URLClassPath.path
+                Field pathField = ucpField.getType().getDeclaredField("path");
+                long pathFieldOffset = unsafe.objectFieldOffset(pathField);
+                ArrayList<URL> path = (ArrayList<URL>) unsafe.getObject(ucpObject, pathFieldOffset);
+
+                return path.toArray(new URL[path.size()]);
+            } catch (Exception e) {
+                e.printStackTrace();
+                return null;
+            }
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/TestRunnerMain.java b/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/TestRunnerMain.java
index fd0ba07..9363ae0 100644
--- a/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/TestRunnerMain.java
+++ b/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/TestRunnerMain.java
@@ -42,21 +42,15 @@ import org.apache.maven.surefire.testset.TestRequest;
 import org.apache.maven.surefire.util.DefaultScanResult;
 
 import java.io.File;
-import java.io.FilenameFilter;
 import java.net.URL;
-import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
-import static java.util.Collections.EMPTY_LIST;
 import static java.util.Collections.emptyList;
 
-/**
- * gongdewei 2020/12/7
- */
 public class TestRunnerMain {
 
     public static void main(String[] args) throws Exception {
@@ -219,9 +213,8 @@ public class TestRunnerMain {
 
     private static Classpath getInprocClasspath() {
         List<String> classpath = new ArrayList<>();
-
         ClassLoader cl = ClassLoader.getSystemClassLoader();
-        URL[] urls = ((URLClassLoader) cl).getURLs();
+        URL[] urls = ClassLoaderUtils.getUrls(cl);
         for (URL url : urls) {
             classpath.add(url.getFile());
         }
diff --git a/test/merge-test-results.sh b/test/merge-test-results.sh
index 082a51b..084bc26 100755
--- a/test/merge-test-results.sh
+++ b/test/merge-test-results.sh
@@ -6,18 +6,24 @@ cd $DIR
 TEST_SUCCESS="TEST SUCCESS"
 TEST_FAILURE="TEST FAILURE"
 
+JAVA_VER=${JAVA_VER:-8}
+echo "JAVA_VER: $JAVA_VER"
+
+RESULT_SUFFIX=result-java${JAVA_VER}.txt
+mergedTestResultFile=jobs/merged-test-$RESULT_SUFFIX
+rm -rf $mergedTestResultFile
+
 echo "All test results:"
-for resultFile in jobs/*result.txt; do
+for resultFile in jobs/*$RESULT_SUFFIX; do
   echo "$resultFile:"
   cat $resultFile
   echo ""
 done
 
-testResultFile=jobs/merged-test-result.txt
-cat jobs/*-result.txt > $testResultFile
-successTest=`grep -c "$TEST_SUCCESS" $testResultFile`
-failedTest=`grep -c "$TEST_FAILURE" $testResultFile`
-totalCount=`grep -c "" $testResultFile`
+cat jobs/*$RESULT_SUFFIX > $mergedTestResultFile
+successTest=`grep -c "$TEST_SUCCESS" $mergedTestResultFile`
+failedTest=`grep -c "$TEST_FAILURE" $mergedTestResultFile`
+totalCount=`grep -c "" $mergedTestResultFile`
 
 echo "----------------------------------------------------------"
 echo "All tests count: $totalCount"
@@ -37,7 +43,7 @@ else
   echo "Exception : some tests fail: $failedTest"
   echo "----------------------------------------------------------"
   echo "Fail tests:"
-  grep "$TEST_FAILURE" jobs/testcases-*-result.txt
+  grep "$TEST_FAILURE" jobs/testjob*$RESULT_SUFFIX
   echo "----------------------------------------------------------"
   exit 1
 fi
diff --git a/test/prepare-test.sh b/test/prepare-test.sh
index 499d6a2..0ad20c4 100755
--- a/test/prepare-test.sh
+++ b/test/prepare-test.sh
@@ -21,7 +21,7 @@ while read file
 do
   job=$((case_index % JOB_COUNT + 1))
   case_index=$((case_index + 1))
-  echo ${file%/$CONFIG_FILE} >> $jobs_dir/testcases-${job}.txt
+  echo ${file%/$CONFIG_FILE} >> $jobs_dir/testjob_${job}.txt
 done < $test_list_file
 
 echo "Total $case_index cases split into $JOB_COUNT jobs:"
diff --git a/test/quick-start_cn.md b/test/quick-start_cn.md
index 00165db..155c95c 100644
--- a/test/quick-start_cn.md
+++ b/test/quick-start_cn.md
@@ -63,14 +63,13 @@ cd dubbo-samples/test
 * 运行全部测试案例
  
   ```
-   BUILD=all  ./run-tests.sh
+   ./run-tests.sh
   ```
  
   run-tests.sh 运行全部测试案例的原理:
 
-  (1) 编译整个dubbo-samples : `BUILD=all`   
-  (2) 查找所有`case-configuration.yml`  
-  (3) fork多进程按顺序运行测试案例
+  (1) 查找所有`case-configuration.yml`  
+  (2) fork多进程按顺序运行测试案例
 
 
 ### 添加测试用例
@@ -258,7 +257,113 @@ services:
 
 请参考文档:[How to convert test cases](convert-case.md)
 
-  
+
+#### 多版本测试
+
+添加一个名称为`case-versions.conf`的文件到测试工程目录下面,与`case-configuration.yml`放到同一个目录。
+此文件用于描述本测试工程支持的组件版本规则,通常使用通配符进行匹配。
+
+**注意:如果用例是针对特定的组件版本,则应该写具体的版本号。**
+
+下面是几种常用的配置:
+
+Spring app 的多版本配置:
+
+```
+# Spring app
+dubbo.version=2.7*, 3.*
+spring.version=4.*, 5.*
+```
+
+SpringBoot 1.x app 的多版本配置:
+
+```
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=1.*
+```
+
+SpringBoot 2.x app 的多版本配置:
+
+```
+# SpringBoot app
+dubbo.version=2.7*, 3.*
+spring-boot.version=2.*
+```
+
+**相关环境变量:**
+
+CANDIDATE_VERSIONS: 候选版本列表,格式请参考下面的例子。
+
+VERSIONS_LIMIT: 设置测试的版本数量限制,超过指定的数量则被截断丢弃。
+
+
+除了dubbo/spring/spring-boot组件,其它有需要测试的组件也可以配置。
+如果要添加新的组件版本需要保证github workflows及`run-tests.sh`的`CANDIDATE_VERSIONS`环境变量包含该组件的候选版本,否则运行测试案例会报错如下:
+
+```
+Component not match
+```
+
+github workflows的候选版本配置格式如下,每行为一个组件的版本列表,也可以用不同的行指定组件不兼容的版本。
+如spring-boot 1.x 和 2.x 不兼容,可以在两行分别配置。
+
+```yaml
+env:
+  #...
+  CANDIDATE_VERSIONS: '
+    dubbo.version: 2.7.8, 2.7.9-SNAPSHOT;
+    spring.version: 4.1.9.RELEASE, 4.2.9.RELEASE, 5.1.20.RELEASE, 5.3.3;
+    spring-boot.version: 1.1.12.RELEASE, 1.2.8.RELEASE, 1.3.8.RELEASE, 1.4.7.RELEASE;
+    spring-boot.version: 2.0.9.RELEASE, 2.1.18.RELEASE, 2.2.12.RELEASE, 2.3.7.RELEASE
+    '
+```
+
+本地开发测试`run-tests.sh`脚本的默认候选版本如下,只测试一个版本:
+
+```
+CANDIDATE_VERSIONS="dubbo.version:2.7.8;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+```
+
+#### 本地测试dubbo 3.0的sample
+
+1、 checkout and build dubbo 3.0
+
+dubbo 3.0 目前还没发正式版本,需要本地编译install到maven repo中:
+
+```
+git clone https://github.com/apache/dubbo.git dubbo3
+cd dubbo3
+git checkout 3.0
+./mvnw -U --batch-mode --no-transfer-progress  clean install -Dmaven.test.skip=true 
+```
+
+2、sample工程添加`case-configuration.yml` 及 `case-versions.conf`
+
+由于这些sample是dubbo 3.0的特性,不兼容2.x,故`case-versions.conf`版本规则如下:
+
+```
+# Spring app
+dubbo.version=3.*
+spring.version=4.*, 5.*
+```
+
+3、设置CANDIDATE_VERSIONS环境变量
+
+候选版本列表中指定dubbo.version为3.0的版本号
+
+```
+export CANDIDATE_VERSIONS="dubbo.version:3.0.0-SNAPSHOT;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+```
+在同一个shell中,只需要执行一次 `export CANDIDATE_VERSIONS=...` 命令,后面多次执行测试案例都会生效。
+
+4、启动测试案例
+
+```
+cd dubbo-samples/test
+./run-test.sh ../dubbo-samples-xxxx
+```
+
 ### 调试运行测试案例
 
   ```
@@ -366,26 +471,6 @@ services:
   构建测试场景,包含`docker-compose.yml`及`scenario.sh`脚本等。
   构建成功后,`scenario.sh`脚本可以单独运行。
 
-#### 编译方式(BUILD)
-
-默认值为`BUILD=case`,即每个case工程单独编译。
-
-* `BUILD=case`  
-
-  单独编译需要运行的测试工程。
-  
-  注意:有部分测试工程因为依赖问题不能独立编译,此时需要改为整体编译或者手工编译。
-
-* `BUILD=all`  
-
-  编译整个dubbo-samples
-  
-* `BUILD=n`  
-
-  不自动编译测试工程,需要先手工编译成功后,再运行测试。
-  
-  Maven编译参数: mvn clean package dependency:copy-dependencies -DskipTests
-
    
 #### scenario测试步骤
 
@@ -394,10 +479,12 @@ services:
   
 * 编译测试工程
   
-  如果按照case单独编译,则执行下面的编译命令:
+  每个case单独编译,编译命令如下:
   
   `mvn clean package dependency:copy-dependencies -DskipTests`
   
+  **注意: 如果是多模块的工程,可以将`case-configuration.yml`放到外层,保证可以独立编译整个case工程。**
+  
 * 生成测试场景
 
   测试场景`scenario_home`的位置位于`${project.basedir}/target`
diff --git a/test/run-tests.sh b/test/run-tests.sh
index 70ba72f..98aed23 100755
--- a/test/run-tests.sh
+++ b/test/run-tests.sh
@@ -4,6 +4,18 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
 abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
 
+trim() {
+    local var="$*"
+    # remove leading whitespace characters
+    var="${var#"${var%%[![:space:]]*}"}"
+    # remove trailing whitespace characters
+    var="${var%"${var##*[![:space:]]}"}"
+    printf '%s' "$var"
+}
+
+JAVA_VER=${JAVA_VER:-8}
+echo "JAVA_VER: $JAVA_VER"
+
 FAIL_FAST=${FAIL_FAST:-0}
 echo "FAIL_FAST: $FAIL_FAST"
 
@@ -14,12 +26,9 @@ echo "SHOW_ERROR_DETAIL: $SHOW_ERROR_DETAIL"
 maxForks=${FORK_COUNT:-2}
 echo "FORK_COUNT: $maxForks"
 
-#Build mode: all, case, no
-BUILD=${BUILD:-case}
-export BUILD=$BUILD
-echo "BUILD: $BUILD"
 
 #debug DEBUG=service1,service2
+#deubg all duboo-xxx: DEBUG=dubbo*
 export DEBUG=$DEBUG
 echo "DEBUG=$DEBUG"
 
@@ -37,7 +46,7 @@ echo "Test reports dir: \${project.basedir}/target/test-reports"
 
 
 #check dubbo/sample-test image and version
-test_image="dubbo/sample-test"
+test_image="dubbo/sample-test:$JAVA_VER"
 echo "Checking test image [$test_image] .. "
 docker images --format 'table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}' | grep $test_image
 result=$?
@@ -51,8 +60,10 @@ fi
 cd $DIR
 
 CONFIG_FILE="case-configuration.yml"
+VERSONS_FILE="case-versions.conf"
 
-testListFile=$DIR/testcases.txt
+mkdir $DIR/jobs
+testListFile=$DIR/jobs/testjob.txt
 targetTestcases=$1
 if [ "$targetTestcases" != "" ];then
   targetTestcases=`abspath $targetTestcases`
@@ -89,23 +100,30 @@ if [ "$DEBUG" != "" ] && [ $caseCount -gt 1 ]; then
 fi
 
 #clear test results
-testResultFile=${testListFile%.*}-result.txt
+testResultFile=${testListFile%.*}-result-java${JAVA_VER}.txt
 rm -f $testResultFile
 echo "Test results: $testResultFile"
 
-if [ "$DUBBO_VERSION" != "" ];then
-  echo "DUBBO_VERSION: $DUBBO_VERSION"
+if [ "$CANDIDATE_VERSIONS" == "" ];then
+  CANDIDATE_VERSIONS="dubbo.version:2.7.8;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+#  CANDIDATE_VERSIONS="dubbo.version:2.7.8;spring.version:4.3.16.RELEASE,5.3.3;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
 fi
-export DUBBO_VERSION=$DUBBO_VERSION
+export CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS
+echo "CANDIDATE_VERSIONS: ${CANDIDATE_VERSIONS[@]}"
 
-if [ "$MVN_OPTS" != "" ];then
+# test combination versions limit of single case
+VERSIONS_LIMIT=${VERSIONS_LIMIT:-4}
+export VERSIONS_LIMIT=$VERSIONS_LIMIT
+echo "VERSIONS_LIMIT: $VERSIONS_LIMIT"
+
+
+if [ "$MVN_OPTS" != "" ]; then
+  export MVN_OPTS=$MVN_OPTS
   echo "MVN_OPTS: $MVN_OPTS"
 fi
-export MVN_OPTS=$MVN_OPTS
 
-BUILD_OPTS="$MVN_OPTS -U --batch-mode --no-transfer-progress clean package dependency:copy-dependencies -DskipTests"
-if [ "$DUBBO_VERSION" != "" ]; then
-  BUILD_OPTS="$BUILD_OPTS -Ddubbo.version=$DUBBO_VERSION"
+if [ "$BUILD_OPTS" == "" ]; then
+  BUILD_OPTS="$MVN_OPTS -U --batch-mode --no-transfer-progress clean package dependency:copy-dependencies -DskipTests"
 fi
 export BUILD_OPTS=$BUILD_OPTS
 echo "BUILD_OPTS: $BUILD_OPTS"
@@ -129,95 +147,137 @@ function print_log_file() {
 }
 
 function process_case() {
-  file=$1
+  case_dir=$1
   case_no=$2
 
-  if [ -d $file ]; then
-    file=$file/$CONFIG_FILE
+  if [ -f $case_dir ]; then
+    case_dir=`dirname $case_dir`
   fi
 
+  file=$case_dir/$CONFIG_FILE
   if [ ! -f $file ]; then
     echo "$TEST_FAILURE: case config not found: $file" | tee -a $testResultFile
     return 1
   fi
 
+  ver_file=$case_dir/$VERSONS_FILE
+  if [ ! -f $ver_file ]; then
+    echo "$TEST_FAILURE: case versions config not found: $ver_file" | tee -a $testResultFile
+    return 1
+  fi
+
+  case_start_time=$SECONDS
   project_home=`dirname $file`
   scenario_home=$project_home/target
   scenario_name=`basename $project_home`
   log_prefix="[${case_no}/${caseCount}] [$scenario_name]"
-  start_time=$SECONDS
   echo "$log_prefix Processing : $project_home .."
 
-  # mvn build
-  if [ "$BUILD" == "case" ]; then
-    echo "$log_prefix Building project : $scenario_name .."
+  # generate version matrix
+  version_matrix_file=$project_home/version-matrix.txt
+  java -DcandidateVersions="$CANDIDATE_VERSIONS" \
+    -DcaseVersionsFile="$ver_file" \
+    -DoutputFile="$version_matrix_file" \
+    -DversionsLimit=$VERSIONS_LIMIT \
+    -cp $test_builder_jar \
+    org.apache.dubbo.scenario.builder.VersionMatcher &> $project_home/version-matrix.log
+  result=$?
+  if [ $result -ne 0 ]; then
+    echo "$log_prefix $TEST_FAILURE: Generate version matrix failure: $project_home/version-matrix.log" | tee -a $testResultFile
+    return 1
+  fi
+
+  version_count=`grep -c "" $version_matrix_file `
+  echo "$log_prefix Version matrix: $version_count"
+  cat $version_matrix_file
+
+  version_no=0
+  while read -r version_profile; do
+    start_time=$SECONDS
+    version_no=$((version_no + 1))
+    log_prefix="[${case_no}/${caseCount}] [$scenario_name:$version_no/$version_count]"
+
+    # run test using version profile
+    echo "$log_prefix Building project : $scenario_name with version: $version_profile .."
     cd $project_home
-    mvn $BUILD_OPTS &> $project_home/mvn.log
+
+    # clean target manual, avoid 'mvn clean' failed with 'Permission denied' in github actions
+    find . -name target -d | xargs -I {} rm -rf {}
+    target_dirs=`find . -name target -d`
+    if [ "$target_dirs" != "" ]; then
+      echo "$log_prefix Force delete target dirs"
+      find . -name target -d | xargs -I {} sudo rm -rf {}
+    fi
+
+    mvn $BUILD_OPTS $version_profile &> $project_home/mvn.log
     result=$?
     if [ $result -ne 0 ]; then
       echo "$log_prefix $TEST_FAILURE: Build failure, please check log: $project_home/mvn.log" | tee -a $testResultFile
+      if [ "$SHOW_ERROR_DETAIL" == "1" ];then
+        cat $project_home/mvn.log
+      fi
       return 1
     fi
-  fi
-
-  #check build
-#  echo "$log_prefix Checking project artifacts .."
-#  if [ ! -d "$project_home/target" ]; then
-#    echo "$log_prefix $TEST_FAILURE: Missing artifacts" | tee -a $testResultFile
-#    return 1
-#  fi
-
-  # generate case configuration
-  mkdir -p $scenario_home/logs
-  echo "$log_prefix Generating test case configuration .."
-  config_time=$SECONDS
-  mkdir -p $scenario_home
-  java -Dconfigure.file=$file \
-    -Dscenario.home=$scenario_home \
-    -Dscenario.name=$scenario_name \
-    -Dscenario.version=$DUBBO_VERSION \
-    -Ddebug.service=$DEBUG \
-    -jar $test_builder_jar  &> $scenario_home/logs/scenario-builder.log
-  result=$?
-  if [ $result -ne 0 ]; then
-    echo "$log_prefix $TEST_FAILURE: Generate case configuration failure: $scenario_home/logs/scenario-builder.log" | tee -a $testResultFile
-    return 1
-  fi
 
-  # run test
-  echo "$log_prefix Running test case .."
-  running_time=$SECONDS
-  bash $scenario_home/scenario.sh
-  result=$?
-  end_time=$SECONDS
+    # generate case configuration
+    mkdir -p $scenario_home/logs
+    echo "$log_prefix Generating test case configuration .."
+    config_time=$SECONDS
+    java -Dconfigure.file=$file \
+      -Dscenario.home=$scenario_home \
+      -Dscenario.name=$scenario_name \
+      -Dscenario.version=$version \
+      -Dtest.image.version=$JAVA_VER \
+      -Ddebug.service=$DEBUG \
+      -jar $test_builder_jar  &> $scenario_home/logs/scenario-builder.log
+    result=$?
+    if [ $result -ne 0 ]; then
+      echo "$log_prefix $TEST_FAILURE: Generate case configuration failure: $scenario_home/logs/scenario-builder.log" | tee -a $testResultFile
+      return 1
+    fi
 
-  if [ $result == 0 ]; then
-    echo "$log_prefix $TEST_SUCCESS: total cost $((end_time - start_time)) s" | tee -a $testResultFile
-  else
-    echo "$log_prefix $TEST_FAILURE, please check logs: $scenario_home/logs" | tee -a $testResultFile
-
-    # show test log
-    if [ "$SHOW_ERROR_DETAIL" == "1" ]; then
-      for log_file in $scenario_home/logs/*.log; do
-        # ignore scenario-builder.log
-        if [[ $log_file != *scenario-builder.log ]]; then
-          print_log_file "$scenario_name : `basename $log_file`" $log_file
-        fi
-      done
+    # run test
+    echo "$log_prefix Running test case .."
+    running_time=$SECONDS
+    bash $scenario_home/scenario.sh
+    result=$?
+    end_time=$SECONDS
+
+    if [ $result == 0 ]; then
+      echo "$log_prefix $TEST_SUCCESS: cost $((end_time - start_time)) s"
+    else
+      echo "$log_prefix $TEST_FAILURE, please check logs: $scenario_home/logs" | tee -a $testResultFile
+
+      # show test log
+      if [ "$SHOW_ERROR_DETAIL" == "1" ]; then
+        for log_file in $scenario_home/logs/*.log; do
+          # ignore scenario-builder.log
+          if [[ $log_file != *scenario-builder.log ]]; then
+            print_log_file "$scenario_name : `basename $log_file`" $log_file
+          fi
+        done
+      fi
+      return 1
     fi
-    return 1
-  fi
+
+  done < $version_matrix_file
+
+  log_prefix="[${case_no}/${caseCount}] [$scenario_name]"
+  echo "$log_prefix $TEST_SUCCESS: versions: $version_count, total cost $((end_time - case_start_time)) s" | tee -a $testResultFile
+
+  # clean log files
+  rm -f $project_home/*.log $project_home/version-matrix.*
 }
 
 # build scenario-builder
 SCENARIO_BUILDER_DIR=$DIR/dubbo-scenario-builder
 echo "Building scenario builder .."
 cd $SCENARIO_BUILDER_DIR
-scenario_mvn_opts="$MVN_OPTS clean package -DskipTests"
 mvn $BUILD_OPTS &> $SCENARIO_BUILDER_DIR/mvn.log
 result=$?
 if [ $result -ne 0 ]; then
   echo "Build dubbo-scenario-builder failure, please check logs: $SCENARIO_BUILDER_DIR/mvn.log"
+  cat $SCENARIO_BUILDER_DIR/mvn.log
   exit $result
 fi
 
@@ -230,18 +290,6 @@ else
   echo "Found test builder : $test_builder_jar"
 fi
 
-# build all samples
-if [ "$BUILD" == "all" ]; then
-  echo "Building dubbo-samples .."
-  cd $DIR/..
-  mvn $BUILD_OPTS
-  result=$?
-  if [ $result -ne 0 ]; then
-    echo "Build dubbo-samples failure, please check logs"
-    exit $result
-  fi
-fi
-
 
 # start run tests
 cd $DIR
@@ -251,11 +299,15 @@ testStartTime=$SECONDS
 allTest=0
 finishedTest=0
 
-while read line
+while read path
 do
   allTest=$((allTest + 1))
+
+  if [ -f $path ];then
+    path=`dirname $path`
+  fi
   # fork process testcase
-  process_case $line $allTest &
+  process_case $path $allTest &
   sleep 1
 
   #wait for tests finished


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org