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 2020/12/25 14:33:22 UTC
[dubbo-samples] branch master updated: Add test framework (#187)
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 63ee96e Add test framework (#187)
63ee96e is described below
commit 63ee96ee0f84eb7f1f4b324c736e40f5034b2af7
Author: gongdewei <ky...@qq.com>
AuthorDate: Fri Dec 25 22:33:12 2020 +0800
Add test framework (#187)
---
.github/workflows/golang-ci.yml | 26 -
.github/workflows/java-ci.yml | 238 ++++++++-
.gitignore | 3 +
dubbo-samples-annotation/case-configuration.yml | 24 +
dubbo-samples-api/case-configuration.yml | 23 +
.../src/main/resources/log4j.properties | 25 +
.../case-configuration.yml | 24 +
.../samples/async/impl/GreetingsServiceImpl.java | 2 +-
.../case-configuration.yml | 24 +
.../dubbo-samples-async-onerror/pom.xml | 13 +
.../src/main/resources/spring/async-consumer.xml | 2 +-
.../dubbo/samples/governance/AsyncServiceIT.java | 33 ++
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
dubbo-samples-attachment/case-configuration.yml | 24 +
dubbo-samples-basic/case-configuration.yml | 24 +
dubbo-samples-cache/case-configuration.yml | 24 +
dubbo-samples-callback/case-configuration.yml | 24 +
dubbo-samples-chain/case-configuration.yml | 58 +++
dubbo-samples-compatible/case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 85 ++++
.../resources/spring/configcenter-consumer.xml | 2 +
.../resources/spring/configcenter-provider.xml | 2 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../resources/spring/configcenter-consumer.xml | 2 +
.../case-configuration.yml | 24 +
.../resources/spring/configcenter-consumer.xml | 2 +
dubbo-samples-echo/case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../dubbo/samples/generic/call/HelloServiceIT.java | 12 +-
.../case-configuration.yml | 24 +
dubbo-samples-group/case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../pom.xml | 3 +-
.../main/resources/spring/metadata-consumer.xml | 2 +
.../main/resources/spring/metadata-provider.xml | 2 +
.../case-configuration.yml | 24 +
dubbo-samples-metrics/case-configuration.yml | 24 +
dubbo-samples-notify/case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../pom.xml | 3 +-
.../case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
.../main/resources/spring/dubbo-demo-provider.xml | 2 +-
.../case-configuration.yml | 24 +
dubbo-samples-stub/case-configuration.yml | 24 +
.../case-configuration.yml | 24 +
test/README.md | 278 +++++++++++
test/build-test-image.sh | 8 +
test/clean-damaged-image.sh | 15 +
test/dubbo-scenario-builder/pom.xml | 97 ++++
.../scenario/builder/AbstractRunningGenerator.java | 68 +++
.../dubbo/scenario/builder/ConfigurationImpl.java | 547 +++++++++++++++++++++
.../builder/DockerComposeRunningGenerator.java | 75 +++
.../dubbo/scenario/builder/IConfiguration.java | 51 ++
.../scenario/builder/ScenarioBuilderMain.java | 28 ++
.../builder/ScenarioRunningScriptGenerator.java | 25 +
.../exception/ConfigureFileNotFoundException.java | 23 +
.../builder/exception/GenerateFailedException.java | 21 +
.../scenario/builder/vo/CaseConfiguration.java | 70 +++
.../dubbo/scenario/builder/vo/DockerService.java | 131 +++++
.../dubbo/scenario/builder/vo/JavaDebugOption.java | 40 ++
.../scenario/builder/vo/ServiceComponent.java | 242 +++++++++
.../main/resources/compose-start-script.template | 18 +
.../resources/configs/app-builtin-zookeeper.yml | 57 +++
.../resources/configs/app-external-zookeeper.yml | 64 +++
.../src/main/resources/docker-compose.template | 88 ++++
.../src/main/resources/scenario.sh | 140 ++++++
test/dubbo-test-runner/build.sh | 19 +
test/dubbo-test-runner/pom.xml | 85 ++++
test/dubbo-test-runner/src/docker/Dockerfile | 61 +++
test/dubbo-test-runner/src/docker/run-dubbo-app.sh | 48 ++
.../dubbo-test-runner/src/docker/run-dubbo-test.sh | 36 ++
test/dubbo-test-runner/src/docker/run.sh | 45 ++
test/dubbo-test-runner/src/docker/utils.sh | 108 ++++
.../apache/dubbo/test/runner/TestRunnerMain.java | 245 +++++++++
test/kill-tests.sh | 19 +
test/pom.xml | 37 ++
test/prepare-test.sh | 28 ++
test/quick-start_cn.md | 102 ++++
test/run-tests.sh | 290 +++++++++++
89 files changed, 4525 insertions(+), 40 deletions(-)
diff --git a/.github/workflows/golang-ci.yml b/.github/workflows/golang-ci.yml
deleted file mode 100644
index 2276c0e..0000000
--- a/.github/workflows/golang-ci.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: Golang CI
-
-on:
- pull_request:
- paths:
- - "golang/**"
- push:
- paths:
- - 'golang/**'
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Set up Go 1.13
- uses: actions/setup-go@v1
- with:
- go-version: 1.13
-
- - name: Check out source code
- uses: actions/checkout@v1
-
- - name: Build
- run: |
- cd golang
- ./ci.sh
\ No newline at end of file
diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml
index 0ed342c..47394b6 100644
--- a/.github/workflows/java-ci.yml
+++ b/.github/workflows/java-ci.yml
@@ -3,22 +3,252 @@ name: Java CI
on:
pull_request:
paths:
- - "java/**"
+ - "**"
push:
paths:
- - 'java/**'
+ - '**'
+
+env:
+ FORK_COUNT: 2
+ FAIL_FAST: 0
+ SHOW_ERROR_DETAIL: 1
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: |
- cd java
./mvnw --settings .mvn/settings.xml clean package
+
+ prepare_test:
+ runs-on: ubuntu-latest
+ env:
+ JOB_COUNT: 6
+ steps:
+ - uses: actions/checkout@v1
+ - name: Prepare test list
+ run: |
+ cd test
+ bash ./prepare-test.sh
+ - name: Upload test list result
+ uses: actions/upload-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs
+
+ test_job_1:
+ needs: prepare_test
+ runs-on: ubuntu-latest
+ env:
+ TEST_CASE_FILE: jobs/testcases-1.txt
+ 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: Download test list result
+ uses: actions/download-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs/
+ - uses: satackey/action-docker-layer-caching@v0.0.11
+ with:
+ key: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ - name: Build test image
+ run: cd test && bash ./build-test-image.sh
+ - name: Run tests
+ run: cd test && bash ./run-tests.sh
+ - name: Clean images
+ run: cd test && bash ./clean-damaged-image.sh
+
+ test_job_2:
+ needs: prepare_test
+ runs-on: ubuntu-latest
+ env:
+ TEST_CASE_FILE: jobs/testcases-2.txt
+ steps:
+ - uses: actions/checkout@v1
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Download test list result
+ uses: actions/download-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs/
+ - uses: satackey/action-docker-layer-caching@v0.0.11
+ with:
+ key: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ - name: Build test image
+ run: cd test && bash ./build-test-image.sh
+ - name: Run tests
+ run: cd test && bash ./run-tests.sh
+ - name: Clean images
+ run: cd test && bash ./clean-damaged-image.sh
+
+ test_job_3:
+ needs: prepare_test
+ runs-on: ubuntu-latest
+ env:
+ TEST_CASE_FILE: jobs/testcases-3.txt
+ 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: Download test list result
+ uses: actions/download-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs/
+ - uses: satackey/action-docker-layer-caching@v0.0.11
+ with:
+ key: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ - name: Build test image
+ run: cd test && bash ./build-test-image.sh
+ - name: Run tests
+ run: cd test && bash ./run-tests.sh
+ - name: Clean images
+ run: cd test && bash ./clean-damaged-image.sh
+
+ test_job_4:
+ needs: prepare_test
+ runs-on: ubuntu-latest
+ env:
+ TEST_CASE_FILE: jobs/testcases-4.txt
+ steps:
+ - uses: actions/checkout@v1
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Download test list result
+ uses: actions/download-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs/
+ - uses: satackey/action-docker-layer-caching@v0.0.11
+ with:
+ key: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ - name: Build test image
+ run: cd test && bash ./build-test-image.sh
+ - name: Run tests
+ run: cd test && bash ./run-tests.sh
+ - name: Clean images
+ run: cd test && bash ./clean-damaged-image.sh
+
+ test_job_5:
+ needs: prepare_test
+ runs-on: ubuntu-latest
+ env:
+ TEST_CASE_FILE: jobs/testcases-5.txt
+ steps:
+ - uses: actions/checkout@v1
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Download test list result
+ uses: actions/download-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs/
+ - uses: satackey/action-docker-layer-caching@v0.0.11
+ with:
+ key: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ - name: Build test image
+ run: cd test && bash ./build-test-image.sh
+ - name: Run tests
+ run: cd test && bash ./run-tests.sh
+ - name: Clean images
+ run: cd test && bash ./clean-damaged-image.sh
+
+ test_job_6:
+ needs: prepare_test
+ runs-on: ubuntu-latest
+ env:
+ TEST_CASE_FILE: jobs/testcases-6.txt
+ steps:
+ - uses: actions/checkout@v1
+ - name: Cache local Maven repository
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Download test list result
+ uses: actions/download-artifact@v2
+ with:
+ name: test-list-result
+ path: test/jobs/
+ - uses: satackey/action-docker-layer-caching@v0.0.11
+ with:
+ key: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ restore-keys: ${{ runner.os }}-docker-layer-${{ hashFiles('**/test/build-test-image.sh') }}
+ - name: Build test image
+ run: cd test && bash ./build-test-image.sh
+ - name: Run tests
+ run: cd test && bash ./run-tests.sh
+ - name: Clean damged images
+ run: cd test && bash ./clean-damaged-image.sh
diff --git a/.gitignore b/.gitignore
index 7905ed6..293c737 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,6 @@ vendor/
logs/
.vscode/
coverage.txt
+
+test/jobs
+testcases*.txt
\ No newline at end of file
diff --git a/dubbo-samples-annotation/case-configuration.yml b/dubbo-samples-annotation/case-configuration.yml
new file mode 100644
index 0000000..4b5f7d6
--- /dev/null
+++ b/dubbo-samples-annotation/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-annotation
+ main_class: org.apache.dubbo.samples.annotation.AnnotationProviderBootstrap
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-api/case-configuration.yml b/dubbo-samples-api/case-configuration.yml
new file mode 100644
index 0000000..bbf9251
--- /dev/null
+++ b/dubbo-samples-api/case-configuration.yml
@@ -0,0 +1,23 @@
+# 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.
+
+from: app-external-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-api
+ main_class: org.apache.dubbo.samples.provider.Application
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-api/src/main/resources/log4j.properties b/dubbo-samples-api/src/main/resources/log4j.properties
new file mode 100644
index 0000000..e976f5c
--- /dev/null
+++ b/dubbo-samples-api/src/main/resources/log4j.properties
@@ -0,0 +1,25 @@
+#
+#
+# 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.
+#
+#
+###set log levels###
+log4j.rootLogger=info, stdout
+###output to the console###
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
\ No newline at end of file
diff --git a/dubbo-samples-async/dubbo-samples-async-generated-future/case-configuration.yml b/dubbo-samples-async/dubbo-samples-async-generated-future/case-configuration.yml
new file mode 100644
index 0000000..d9df910
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-generated-future/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-async-generated-future
+ main_class: org.apache.dubbo.samples.async.AsyncProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-async/dubbo-samples-async-generated-future/src/main/java/org/apache/dubbo/samples/async/impl/GreetingsServiceImpl.java b/dubbo-samples-async/dubbo-samples-async-generated-future/src/main/java/org/apache/dubbo/samples/async/impl/GreetingsServiceImpl.java
index 0d414c8..fe0340e 100644
--- a/dubbo-samples-async/dubbo-samples-async-generated-future/src/main/java/org/apache/dubbo/samples/async/impl/GreetingsServiceImpl.java
+++ b/dubbo-samples-async/dubbo-samples-async-generated-future/src/main/java/org/apache/dubbo/samples/async/impl/GreetingsServiceImpl.java
@@ -28,7 +28,7 @@ public class GreetingsServiceImpl implements GreetingService {
public String greeting(String name) {
System.out.println("provider received: " + name);
try {
- Thread.sleep(500);
+ Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
diff --git a/dubbo-samples-async/dubbo-samples-async-onerror/case-configuration.yml b/dubbo-samples-async/dubbo-samples-async-onerror/case-configuration.yml
new file mode 100644
index 0000000..5244d7d
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-onerror/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-async-onerror
+ main_class: org.apache.dubbo.samples.governance.AsyncProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-async/dubbo-samples-async-onerror/pom.xml b/dubbo-samples-async/dubbo-samples-async-onerror/pom.xml
index 16ffe54..bfb331b 100644
--- a/dubbo-samples-async/dubbo-samples-async-onerror/pom.xml
+++ b/dubbo-samples-async/dubbo-samples-async-onerror/pom.xml
@@ -209,6 +209,19 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
diff --git a/dubbo-samples-async/dubbo-samples-async-onerror/src/main/resources/spring/async-consumer.xml b/dubbo-samples-async/dubbo-samples-async-onerror/src/main/resources/spring/async-consumer.xml
index b6dcca0..d584894 100644
--- a/dubbo-samples-async/dubbo-samples-async-onerror/src/main/resources/spring/async-consumer.xml
+++ b/dubbo-samples-async/dubbo-samples-async-onerror/src/main/resources/spring/async-consumer.xml
@@ -26,7 +26,7 @@
<dubbo:application name="async-consumer"/>
- <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
+ <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
<dubbo:reference cluster="failfast" async="true" id="asyncService" interface="org.apache.dubbo.samples.governance.api.AsyncService"/>
diff --git a/dubbo-samples-async/dubbo-samples-async-onerror/src/test/java/org/apache/dubbo/samples/governance/AsyncServiceIT.java b/dubbo-samples-async/dubbo-samples-async-onerror/src/test/java/org/apache/dubbo/samples/governance/AsyncServiceIT.java
new file mode 100644
index 0000000..548bb99
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-onerror/src/test/java/org/apache/dubbo/samples/governance/AsyncServiceIT.java
@@ -0,0 +1,33 @@
+package org.apache.dubbo.samples.governance;
+
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.samples.governance.api.AsyncService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {"classpath:/spring/async-consumer.xml"})
+public class AsyncServiceIT {
+
+ @Autowired
+ private AsyncService asyncService;
+
+ @Test(expected = org.apache.dubbo.remoting.TimeoutException.class)
+ public void testSayHelloTimeout() throws Throwable {
+ try {
+ asyncService.sayHelloTimeout("timeout world");
+ CompletableFuture<String> helloFuture = RpcContext.getContext().getCompletableFuture();
+ String result = helloFuture.get();
+ System.out.println("result: "+result);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw e.getCause();
+ }
+ }
+}
diff --git a/dubbo-samples-async/dubbo-samples-async-original-future/case-configuration.yml b/dubbo-samples-async/dubbo-samples-async-original-future/case-configuration.yml
new file mode 100644
index 0000000..4fbaa35
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-original-future/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-async-original-future
+ main_class: org.apache.dubbo.samples.async.AsyncProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-async/dubbo-samples-async-provider/case-configuration.yml b/dubbo-samples-async/dubbo-samples-async-provider/case-configuration.yml
new file mode 100644
index 0000000..df96773
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-provider/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-async-provider
+ main_class: org.apache.dubbo.samples.async.AsyncProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-async/dubbo-samples-async-simple/case-configuration.yml b/dubbo-samples-async/dubbo-samples-async-simple/case-configuration.yml
new file mode 100644
index 0000000..14b9858
--- /dev/null
+++ b/dubbo-samples-async/dubbo-samples-async-simple/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-async-simple
+ main_class: org.apache.dubbo.samples.async.AsyncProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-attachment/case-configuration.yml b/dubbo-samples-attachment/case-configuration.yml
new file mode 100644
index 0000000..a87cbb0
--- /dev/null
+++ b/dubbo-samples-attachment/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-attachment
+ main_class: org.apache.dubbo.samples.attachment.AttachmentProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-basic/case-configuration.yml b/dubbo-samples-basic/case-configuration.yml
new file mode 100644
index 0000000..b88c91d
--- /dev/null
+++ b/dubbo-samples-basic/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-basic
+ main_class: org.apache.dubbo.samples.basic.BasicProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-cache/case-configuration.yml b/dubbo-samples-cache/case-configuration.yml
new file mode 100644
index 0000000..a0795d4
--- /dev/null
+++ b/dubbo-samples-cache/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-cache
+ main_class: org.apache.dubbo.samples.cache.CacheProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-callback/case-configuration.yml b/dubbo-samples-callback/case-configuration.yml
new file mode 100644
index 0000000..073f207
--- /dev/null
+++ b/dubbo-samples-callback/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-callback
+ main_class: org.apache.dubbo.samples.callback.CallbackProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-chain/case-configuration.yml b/dubbo-samples-chain/case-configuration.yml
new file mode 100644
index 0000000..fd33829
--- /dev/null
+++ b/dubbo-samples-chain/case-configuration.yml
@@ -0,0 +1,58 @@
+# 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.
+
+
+services:
+ zookeeper:
+ image: zookeeper:latest
+
+ dubbo-samples-chain-backend:
+ type: app
+ basedir: dubbo-samples-chain-backend
+ mainClass: org.apache.dubbo.samples.chain.BackendProvider
+ systemProps:
+ - zookeeper.address=zookeeper
+ waitPortsBeforeRun:
+ - zookeeper:2181
+ depends_on:
+ - zookeeper
+
+ dubbo-samples-chain-middle:
+ type: app
+ basedir: dubbo-samples-chain-middle
+ mainClass: org.apache.dubbo.samples.chain.MiddleEndProvider
+ systemProps:
+ - zookeeper.address=zookeeper
+ waitPortsBeforeRun:
+ - zookeeper:2181
+ depends_on:
+ - zookeeper
+
+ dubbo-samples-chain-front:
+ type: test
+ basedir: dubbo-samples-chain-front
+ tests:
+ - "**/*IT.class"
+ systemProps:
+ - zookeeper.address=zookeeper
+ waitPortsBeforeRun:
+ - zookeeper:2181
+ - dubbo-samples-chain-backend:20880
+ - dubbo-samples-chain-middle:20881
+ depends_on:
+ - zookeeper
+ - dubbo-samples-chain-backend
+ - dubbo-samples-chain-middle
diff --git a/dubbo-samples-compatible/case-configuration.yml b/dubbo-samples-compatible/case-configuration.yml
new file mode 100644
index 0000000..03331ea
--- /dev/null
+++ b/dubbo-samples-compatible/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-compatible
+ main_class: org.apache.dubbo.samples.compat.Provider
+ zookeeper_port: 2181
+ dubbo_port: 20890
+
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-annotation/case-configuration.yml b/dubbo-samples-configcenter/dubbo-samples-configcenter-annotation/case-configuration.yml
new file mode 100644
index 0000000..da2a1ac
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-annotation/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-configcenter-annotation
+ main_class: org.apache.dubbo.samples.configcenter.annotation.AnnotationProvider
+ zookeeper_port: 2181
+ dubbo_port: 20990
+
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/case-configuration.yml b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/case-configuration.yml
new file mode 100644
index 0000000..d715f8e
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/case-configuration.yml
@@ -0,0 +1,85 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+timeout: 120
+
+props:
+ project_name: dubbo-samples-configcenter-apollo
+ main_class: org.apache.dubbo.samples.configcenter.ApolloProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+ apollo_address: apollo-quick-start
+ apollo_port: 8080
+
+services:
+ ${project_name}:
+ type: app
+ basedir: .
+ mainClass: ${main_class}
+ systemProps:
+ - apollo.address=${apollo_address}
+ - apollo.port=${apollo_port}
+ waitPortsBeforeRun:
+ - ${apollo_address}:${apollo_port}
+ checkTimeout: 100
+
+ ${project_name}-test:
+ type: test
+ basedir: .
+ tests:
+ - "**/*IT.class"
+ systemProps:
+ - zookeeper.address=${project_name}
+ - zookeeper.port=${zookeeper_port}
+ - dubbo.address=${project_name}
+ - dubbo.port=${dubbo_port}
+ waitPortsBeforeRun:
+ - ${project_name}:${zookeeper_port}
+ - ${project_name}:${dubbo_port}
+ checkTimeout: 100
+ depends_on:
+ - ${project_name}
+
+ apollo-quick-start:
+ image: nobodyiam/apollo-quick-start
+ depends_on:
+ - apollo-db
+# ports:
+# - "8080:8080"
+# - "8070:8070"
+ links:
+ - apollo-db
+
+ apollo-db:
+ image: mysql:5.7
+ environment:
+ - TZ=Asia/Shanghai
+ - MYSQL_ALLOW_EMPTY_PASSWORD=yes
+# ports:
+# - "13306:3306"
+ volumes:
+ - ./classes/docker/sql:/docker-entrypoint-initdb.d
+# - ./sql_data:/var/lib/mysql
+# volumes_from:
+# - apollo-dbdata
+# depends_on:
+# - apollo-dbdata
+#
+# apollo-dbdata:
+# image: alpine:latest
+# volumes:
+# - /var/lib/mysql
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-consumer.xml b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-consumer.xml
index 92965eb..4b25a6f 100644
--- a/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-consumer.xml
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-consumer.xml
@@ -27,6 +27,8 @@
<dubbo:application name="dubbo-configcenter-apollo-consumer"/>
+ <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+
<dubbo:config-center highest-priority="false" protocol="apollo" address="${apollo.address:localhost}:8080"/>
<dubbo:reference id="demoService" interface="org.apache.dubbo.samples.configcenter.api.DemoService"/>
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-provider.xml b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-provider.xml
index de2b0ea..6f0bfbb 100644
--- a/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-provider.xml
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-apollo/src/main/resources/spring/configcenter-provider.xml
@@ -27,6 +27,8 @@
<dubbo:application name="dubbo-configcenter-apollo-provider"/>
+ <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+
<dubbo:config-center address="apollo://${apollo.address:localhost}:8080"/>
<bean id="demoService" class="org.apache.dubbo.samples.configcenter.impl.DemoServiceImpl"/>
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-externalconfiguration/case-configuration.yml b/dubbo-samples-configcenter/dubbo-samples-configcenter-externalconfiguration/case-configuration.yml
new file mode 100644
index 0000000..275dfa6
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-externalconfiguration/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-configcenter-externalconfiguration
+ main_class: org.apache.dubbo.samples.externalconfiguration.provider.AnnotationProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/case-configuration.yml b/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/case-configuration.yml
new file mode 100644
index 0000000..b312f37
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-configcenter-multiprotocol
+ main_class: org.apache.dubbo.samples.configcenter.BasicProvider
+ zookeeper_port: 2181
+ dubbo_port: 20991
+
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/src/main/resources/spring/configcenter-consumer.xml b/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/src/main/resources/spring/configcenter-consumer.xml
index c6170b7..f3fdd7c 100644
--- a/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/src/main/resources/spring/configcenter-consumer.xml
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-multiprotocol/src/main/resources/spring/configcenter-consumer.xml
@@ -27,6 +27,8 @@
<dubbo:config-center address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+ <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+
<dubbo:reference id="demoService" protocol="dubbo"
interface="org.apache.dubbo.samples.configcenter.api.DemoService"/>
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/case-configuration.yml b/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/case-configuration.yml
new file mode 100644
index 0000000..2a946e8
--- /dev/null
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-configcenter-xml
+ main_class: org.apache.dubbo.samples.configcenter.BasicProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/src/main/resources/spring/configcenter-consumer.xml b/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/src/main/resources/spring/configcenter-consumer.xml
index 2c5dc3e..3d57adb 100644
--- a/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/src/main/resources/spring/configcenter-consumer.xml
+++ b/dubbo-samples-configcenter/dubbo-samples-configcenter-xml/src/main/resources/spring/configcenter-consumer.xml
@@ -30,6 +30,8 @@
<dubbo:config-center highest-priority="false" address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+ <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+
<dubbo:reference group="*" id="demoService" interface="org.apache.dubbo.samples.configcenter.api.DemoService"/>
</beans>
diff --git a/dubbo-samples-echo/case-configuration.yml b/dubbo-samples-echo/case-configuration.yml
new file mode 100644
index 0000000..1fd027a
--- /dev/null
+++ b/dubbo-samples-echo/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-echo
+ main_class: org.apache.dubbo.samples.echo.EchoProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/case-configuration.yml b/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/case-configuration.yml
new file mode 100644
index 0000000..17fbefd
--- /dev/null
+++ b/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-generic-impl-provider
+ main_class: org.apache.dubbo.samples.generic.call.GenericImplProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/src/test/java/org/apache/dubbo/samples/generic/call/HelloServiceIT.java b/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/src/test/java/org/apache/dubbo/samples/generic/call/HelloServiceIT.java
index 7e1d4b0..78575c1 100644
--- a/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/src/test/java/org/apache/dubbo/samples/generic/call/HelloServiceIT.java
+++ b/dubbo-samples-generic/dubbo-samples-generic-impl/dubbo-samples-generic-impl-provider/src/test/java/org/apache/dubbo/samples/generic/call/HelloServiceIT.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.samples.generic.call;
+import org.apache.dubbo.rpc.service.GenericException;
import org.apache.dubbo.samples.generic.call.api.HelloService;
import org.junit.Assert;
@@ -42,8 +43,13 @@ public class HelloServiceIT {
Assert.assertEquals("sayHelloAsync: hello world", helloService.sayHelloAsync("world").get());
}
- @Test(expected = UnsupportedOperationException.class)
- public void testNotImplementedHello() throws Exception {
- helloService.notImplementedHello("dubbo");
+ @Test
+ public void testNotImplementedHello() throws Throwable {
+ try {
+ helloService.notImplementedHello("dubbo");
+ Assert.fail("expect java.lang.UnsupportedOperationException");
+ } catch (GenericException e) {
+ Assert.assertEquals("java.lang.UnsupportedOperationException", e.getExceptionClass());
+ }
}
}
diff --git a/dubbo-samples-generic/dubbo-samples-generic-type/case-configuration.yml b/dubbo-samples-generic/dubbo-samples-generic-type/case-configuration.yml
new file mode 100644
index 0000000..f4a0366
--- /dev/null
+++ b/dubbo-samples-generic/dubbo-samples-generic-type/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-generic-type
+ main_class: org.apache.dubbo.samples.generic.GenericProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-group/case-configuration.yml b/dubbo-samples-group/case-configuration.yml
new file mode 100644
index 0000000..493a29d
--- /dev/null
+++ b/dubbo-samples-group/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-group
+ main_class: org.apache.dubbo.samples.group.GroupProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/case-configuration.yml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/case-configuration.yml
new file mode 100644
index 0000000..3f48ed7
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-configcenter/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-metadata-report-configcenter
+ main_class: org.apache.dubbo.samples.metadatareport.configcenter.MetadataConfigcenterProvider
+ zookeeper_port: 2181
+ dubbo_port: 20831
+
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotation/case-configuration.yml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotation/case-configuration.yml
new file mode 100644
index 0000000..32c8b26
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-annotation/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-metadata-report-local-annotation
+ main_class: org.apache.dubbo.samples.metadatareport.local.annotation.MetadataLocalAnnotationProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/case-configuration.yml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/case-configuration.yml
new file mode 100644
index 0000000..a097dc9
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-metadata-report-local-properties
+ main_class: org.apache.dubbo.samples.metadatareport.local.properties.MetadataLocalPropertiesProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/pom.xml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/pom.xml
index e696083..9c87778 100644
--- a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/pom.xml
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/pom.xml
@@ -41,8 +41,7 @@
<java-image.name>openjdk:8</java-image.name>
<dubbo.port>20880</dubbo.port>
<zookeeper.port>2181</zookeeper.port>
- <main-class>org.apache.dubbo.samples.metadatareport.local.properties.MetadataLocalPropertiesProvider
- </main-class>
+ <main-class>org.apache.dubbo.samples.metadatareport.local.properties.MetadataLocalPropertiesProvider</main-class>
</properties>
<dependencies>
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-consumer.xml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-consumer.xml
index a5cd6e6..43373eb 100644
--- a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-consumer.xml
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-consumer.xml
@@ -27,6 +27,8 @@
<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+ <dubbo:metadata-report address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+
<dubbo:reference id="demoService"
interface="org.apache.dubbo.samples.metadatareport.local.properties.api.DemoService"/>
</beans>
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-provider.xml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-provider.xml
index de5fa2c..198d43a 100644
--- a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-provider.xml
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-properties/src/main/resources/spring/metadata-provider.xml
@@ -27,6 +27,8 @@
<dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+ <dubbo:metadata-report address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>
+
<bean id="demoService" class="org.apache.dubbo.samples.metadatareport.local.properties.impl.DemoServiceImpl"/>
<dubbo:service interface="org.apache.dubbo.samples.metadatareport.local.properties.api.DemoService"
ref="demoService"/>
diff --git a/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/case-configuration.yml b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/case-configuration.yml
new file mode 100644
index 0000000..569853e
--- /dev/null
+++ b/dubbo-samples-metadata-report/dubbo-samples-metadata-report-local-xml/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-metadata-report-local-xml
+ main_class: org.apache.dubbo.samples.metadatareport.local.xml.MetadataLocalXmlProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-metrics/case-configuration.yml b/dubbo-samples-metrics/case-configuration.yml
new file mode 100644
index 0000000..bd9c7f4
--- /dev/null
+++ b/dubbo-samples-metrics/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-metrics
+ main_class: org.apache.dubbo.samples.metrics.MetricsProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-notify/case-configuration.yml b/dubbo-samples-notify/case-configuration.yml
new file mode 100644
index 0000000..5e426db
--- /dev/null
+++ b/dubbo-samples-notify/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-notify
+ main_class: org.apache.dubbo.samples.notify.NotifyProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-serialization/dubbo-samples-serialization-java/case-configuration.yml b/dubbo-samples-serialization/dubbo-samples-serialization-java/case-configuration.yml
new file mode 100644
index 0000000..04fd717
--- /dev/null
+++ b/dubbo-samples-serialization/dubbo-samples-serialization-java/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-serialization-java
+ main_class: org.apache.dubbo.samples.serialization.DubboProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation/case-configuration.yml b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation/case-configuration.yml
new file mode 100644
index 0000000..6391ff1
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-annotation/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-simplified-registry-annotation
+ main_class: org.apache.dubbo.samples.simplified.annotation.SimpleRegistryAnnotationProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple/case-configuration.yml b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple/case-configuration.yml
new file mode 100644
index 0000000..17b3a6e
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-nosimple/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-simplified-registry-nosimple
+ main_class: org.apache.dubbo.samples.simplified.registry.nosimple.NoSimpleRegistryProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/case-configuration.yml b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/case-configuration.yml
new file mode 100644
index 0000000..1686b0c
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-simplified-registry-properties
+ main_class: org.apache.dubbo.samples.simplified.registry.properties.SimpleRegistryPropertiesProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/pom.xml b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/pom.xml
index d094a8a..7887573 100644
--- a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/pom.xml
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-properties/pom.xml
@@ -43,8 +43,7 @@
<java-image.name>openjdk:8</java-image.name>
<dubbo.port>20880</dubbo.port>
<zookeeper.port>2181</zookeeper.port>
- <main-class>org.apache.dubbo.samples.simplified.registry.properties.SimpleRegistryPropertiesProvider
- </main-class>
+ <main-class>org.apache.dubbo.samples.simplified.registry.properties.SimpleRegistryPropertiesProvider</main-class>
</properties>
<dependencies>
diff --git a/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml/case-configuration.yml b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml/case-configuration.yml
new file mode 100644
index 0000000..8a54af1
--- /dev/null
+++ b/dubbo-samples-simplified-registry/dubbo-samples-simplified-registry-xml/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-simplified-registry-xml
+ main_class: org.apache.dubbo.samples.simplified.registry.xml.SimpleRegistryXmlProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-spi-compatible/case-configuration.yml b/dubbo-samples-spi-compatible/case-configuration.yml
new file mode 100644
index 0000000..11b34bd
--- /dev/null
+++ b/dubbo-samples-spi-compatible/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-spi-compatible
+ main_class: org.apache.dubbo.samples.basic.SpiCompatibleProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-spi-compatible/src/main/resources/spring/dubbo-demo-provider.xml b/dubbo-samples-spi-compatible/src/main/resources/spring/dubbo-demo-provider.xml
index 5aa7c46..5718f81 100644
--- a/dubbo-samples-spi-compatible/src/main/resources/spring/dubbo-demo-provider.xml
+++ b/dubbo-samples-spi-compatible/src/main/resources/spring/dubbo-demo-provider.xml
@@ -25,7 +25,7 @@
<dubbo:application name="compatibility-provider"/>
- <dubbo:registry protocol="compatible" address="127.0.0.1:2181"/>
+ <dubbo:registry protocol="compatible" address="${zookeeper.address:127.0.0.1}:2181"/>
<dubbo:protocol name="compatible" port="20880"/>
diff --git a/dubbo-samples-spring-boot-hystrix/case-configuration.yml b/dubbo-samples-spring-boot-hystrix/case-configuration.yml
new file mode 100644
index 0000000..8a1f01e
--- /dev/null
+++ b/dubbo-samples-spring-boot-hystrix/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-spring-boot-hystrix
+ main_class: org.apache.dubbo.spring.boot.provider.ProviderApplication
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-stub/case-configuration.yml b/dubbo-samples-stub/case-configuration.yml
new file mode 100644
index 0000000..4beb313
--- /dev/null
+++ b/dubbo-samples-stub/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-stub
+ main_class: org.apache.dubbo.samples.stub.StubProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/dubbo-samples-switch-serialization-thread/case-configuration.yml b/dubbo-samples-switch-serialization-thread/case-configuration.yml
new file mode 100644
index 0000000..f798350
--- /dev/null
+++ b/dubbo-samples-switch-serialization-thread/case-configuration.yml
@@ -0,0 +1,24 @@
+# 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.
+
+from: app-builtin-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-switch-serialization-thread
+ main_class: org.apache.dubbo.samples.serialization.change.thread.SerializationSwitchThreadProvider
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 0000000..a37cd98
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,278 @@
+## Dubbo Integration Test
+
+### Test steps
+
+Follow the 3 steps below:
+
+#### Step 1 - Build test image
+
+Please install `docker` and `docker-compose` first, then build the test image.
+
+```
+cd dubbo-samples/test
+./build-test-image.sh
+```
+Rebuild the image after modify any file of the `dubbo-test-runner` project.
+
+#### Step 2 - Add case configuration
+Add a `case-configuration.yml` to the tested project, for examples:
+
+```
+from: app-builtin-zookeeper.yml
+props:
+ project_name: dubbo-samples-annotation
+ main_class: org.apache.dubbo.samples.annotation.AnnotationProviderBootstrap
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
+```
+
+Some example projects:
+
+ * [dubbo-samples-annotation](../dubbo-samples-annotation/case-configuration.yml) : A simple provider service with builtin zookeeper.
+ * [dubbo-samples-chain](../dubbo-samples-chain/case-configuration.yml) : A multiple services with external zookeeper.
+
+#### Step 3 - Generate and test scenario
+
+```
+cd dubbo-samples/test
+./run-tests.sh
+```
+
+### Builtin parent configuration
+
+Use `from` directive can import parent configuration, merge into current configuration.
+
+Builtin parent configurations is in directory: `test/dubbo-scenario-builder/src/main/resources/configs`.
+
+* `app-builtin-zookeeper.yml`
+
+ Applicable scenario: single dubbo provider application with builtin zookeeper
+and test case.
+
+* `app-external-zookeeper.yml`
+ Applicable scenario: single dubbo provider application, external zookeeper
+and test case.
+
+
+**Usages:**
+
+* `dubbo-samples-annotation` configuration:
+
+```
+from: app-builtin-zookeeper.yml
+props:
+ project_name: dubbo-samples-annotation
+ main_class: org.apache.dubbo.samples.annotation.AnnotationProviderBootstrap
+ zookeeper_port: 2181
+ dubbo_port: 20880
+```
+
+`project_name` : project name of dubbo sample
+
+`main_class` : main class of dubbo provider application
+
+`dubbo_port` : dubbo provider service port
+
+`zookeeper_port` : builtin zookeeper port
+
+
+* `dubbo-samples-api` configuration:
+
+```
+from: app-external-zookeeper.yml
+
+props:
+ project_name: dubbo-samples-api
+ main_class: org.apache.dubbo.samples.provider.Application
+ dubbo_port: 20880
+ zookeeper_version: latest
+```
+
+`zookeeper_version` : external zookeeper version
+
+External zookeeper service is a fixed port 2181, cause cannot change port unless expose it.
+
+
+### Case configuration details
+
+Top level directives:
+
+| Name | Description |
+| ---- | ----------- |
+| `from` | load parent case configuration, cover its `props` with current configration |
+| `props` | Internal properties, automatically replace the current configuration or inherited configuration variables when parsing |
+| `services` | A set of app/test services or external services |
+
+
+Directives for dubbo service:
+
+| Name | Description | Defaults |
+| ---- | ----------- | -------- |
+| `type` | service type: `app` - dubbo provider application; `test`- dubbo testcase | |
+| `basedir` | project basedir of app/test service | `.` (current dir) |
+| `mainClass` | Main class of provider service, only for app service. | |
+| `systemProps` | set Java app system properties, automatically converted to jvm flags: `-Dname=value` | |
+| `jvmFlags` | multiple jvm flags, automatically join as one string | |
+| `waitPortsBeforeRun` | Wait ports before run app/test | |
+| `tests` | Matching test patterns, only for test service. | |
+| | | |
+
+
+Service directives compatible with `docker-compose`:
+
+| Name | Description | Defaults |
+| ---- | ----------- | -------- |
+| `image` | docker image name of container | app/test service is implicitly set to `dubbo/sample-test`. |
+| `environment` | |
+| `depends_on` | |
+| `hostname` | container hostname | app/test service is implicitly set to service id |
+| `volumes` | container mount points | app/test service automatically mounts directory: `$basedir/target:/usr/local/dubbo/app` |
+| `links` | |
+| `expose` | expose ports between containers |
+| `ports` | mapping ports to host os |
+| `entrypoint` | |
+| `healthcheck` | |
+
+
+#### Configuration example
+
+`app-external-zookeeper.yml` includes :
+
+* External zookeeper
+* Dubbo provider application
+* Dubbo testcase
+
+**Note:**
+
+* app/test service connect to zookeeper by system property `zookeeper.address` and `zookeeper.port`
+
+* wait zookeeper port before run dubbo provider application
+
+* wait zookeeper port and dubbo provider service port before run dubbo test
+
+```
+props:
+# project_name: dubbo-samples-xxx
+# main_class: org.apache.dubbo.samples.xxx.XxxProviderBootstrap
+ dubbo_port: 20880
+ zookeeper_version: latest
+
+services:
+ zookeeper:
+ image: zookeeper:${zookeeper_version}
+
+ ${project_name}:
+ type: app
+ basedir: .
+ mainClass: ${main_class}
+ systemProps:
+ - zookeeper.address=zookeeper
+ - zookeeper.port=2181
+ waitPortsBeforeRun:
+ - zookeeper:2181
+
+ ${project_name}-test:
+ type: test
+ basedir: .
+ tests:
+ - "**/*IT.class"
+ systemProps:
+ - zookeeper.address=zookeeper
+ - zookeeper.port=2181
+ waitPortsBeforeRun:
+ - zookeeper:2181
+ - ${project_name}:${dubbo_port}
+ depends_on:
+ - ${project_name}
+
+```
+
+
+### Some tricks
+
+#### Scenario
+
+A scenario is a complete test environment, including docker-compose.yml, scenario.sh, app classes, test classes and dependency jars. You can test the scenario separately, just run scenario.sh.
+
+* Scenario home
+
+ `${scenario_home}` default location is: `${project.basedir/target}`.
+
+ App / test service automatically mounts directory: `${scenario_home}:/usr/local/dubbo/app`
+
+
+* Scenario running timeout
+
+ Default running timeout is 90s. Some test cases require more time, you can modify it in the following way.
+
+ (1) Change timeout in `case-configuration.yml`:
+
+ ```
+ timeout: 120
+ ```
+
+ (2) Change timeout in command line
+
+ ```
+ timeout=120 bash ${scenario_home}/scenario.sh
+ ```
+
+#### Logs
+
+* Container log
+ Container log location is: `${scenario_home}/logs/${serviceName}.log`, include of dubbo app/test
+ service and external service.
+
+* Scenario log
+ Script `scenario.sh` log location: `${scenario_home}/logs/scenario.log`.
+
+* Scenario builder log
+ Scenario builder log location: `$scenario_home/logs/scenario-builder.log`
+
+#### Test reports
+
+The test reports is in directory: `${scenario_home}/test-reports`
+
+#### Fork run
+
+The fork count is 2 by default, you can modify it by setting env `FORK_COUNT=n`.
+Increasing the fork count may cause the container to run very slowly,
+please set it according to the CPU/IO performance of the operating system.
+
+```
+FORK_COUNT=2 bash run-tests.sh
+```
+
+#### Fail-fast
+
+Run tests in fail-fast mode, abort testing when any case is failed.
+It's useful when running tests in CI server, such as: Jenkins, Github actions.
+Default value: `FAIL_FAST=0`.
+
+```
+FAIL_FAST=1 bash run-tests.sh
+```
+
+#### Show error detail
+
+Show log detail of failed testcase, including app log and test container log.
+It's useful when running tests in CI server, such as: Jenkins, Github actions.
+Default value: `SHOW_ERROR_DETAIL=0`.
+
+```
+SHOW_ERROR_DETAIL=1 bash run-tests.sh
+```
+
+### Develop
+
+#### dubbo-scenario-builder
+Build dubbo test scenario, generating docker/docker-compose script files and
+start script files.
+
+
+#### dubbo-test-runner
+A Junit test runner, execute a set of testcases, replacement for maven-safefail-plugin.
+Also include files for `dubbo-test-image`.
+
+
diff --git a/test/build-test-image.sh b/test/build-test-image.sh
new file mode 100755
index 0000000..2020d7d
--- /dev/null
+++ b/test/build-test-image.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Note: modify follow comment when need refresh github actions docker layer caching
+# dubbo/sample-test updated: 2020.12.25
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+$DIR/dubbo-test-runner/build.sh
\ No newline at end of file
diff --git a/test/clean-damaged-image.sh b/test/clean-damaged-image.sh
new file mode 100755
index 0000000..8903c90
--- /dev/null
+++ b/test/clean-damaged-image.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+echo "Killing dubbo containers .."
+docker ps -a | grep dubbo | awk '{ print $1}' | xargs -I {} docker kill {}
+
+echo "Removing dubbo containers .."
+docker ps -a | grep dubbo | awk '{ print $1}' | xargs -I {} docker rm {}
+
+#echo "Removing dubbo images .."
+#docker images | grep dubbo | awk '{ print $3}' | xargs -I {} docker rmi {}
+
+echo "Removing damaged images .."
+docker image prune -f
diff --git a/test/dubbo-scenario-builder/pom.xml b/test/dubbo-scenario-builder/pom.xml
new file mode 100644
index 0000000..eaf7c87
--- /dev/null
+++ b/test/dubbo-scenario-builder/pom.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>dubbo-test</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-scenario-builder</artifactId>
+
+ <properties>
+ <snakeyaml.version>1.24</snakeyaml.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>3.0.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.28</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.yaml</groupId>
+ <artifactId>snakeyaml</artifactId>
+ <version>${snakeyaml.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.11</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.25</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>log4j-over-slf4j</artifactId>
+ <version>1.7.25</version>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>3.3.0</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <archive>
+ <manifest>
+ <mainClass>org.apache.dubbo.scenario.builder.ScenarioBuilderMain</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id> <!-- this is used for inheritance merges -->
+ <phase>package</phase> <!-- bind to the packaging phase -->
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/AbstractRunningGenerator.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/AbstractRunningGenerator.java
new file mode 100644
index 0000000..4ed7101
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/AbstractRunningGenerator.java
@@ -0,0 +1,68 @@
+/*
+ * 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 freemarker.template.Configuration;
+import freemarker.template.TemplateExceptionHandler;
+import org.apache.dubbo.scenario.builder.exception.GenerateFailedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.lang.invoke.MethodHandles;
+import java.util.Map;
+
+public abstract class AbstractRunningGenerator implements ScenarioRunningScriptGenerator {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ protected final Configuration cfg;
+
+ protected AbstractRunningGenerator() {
+ cfg = new Configuration(Configuration.VERSION_2_3_28);
+ try {
+ cfg.setClassLoaderForTemplateLoading(this.getClass().getClassLoader(), "/");
+ cfg.setDefaultEncoding("UTF-8");
+ cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
+ cfg.setLogTemplateExceptions(false);
+ cfg.setWrapUncheckedExceptions(true);
+ cfg.setNumberFormat("computer");
+ } catch (Exception e) {
+ // never to do this
+ }
+ }
+
+ @Override
+ public final void generate(IConfiguration configuration) throws GenerateFailedException {
+ generateAdditionFiles(configuration);
+
+ final Map<String, Object> root = configuration.toMap();
+ root.put("running_script", runningScript(configuration));
+
+ String scriptPath = configuration.outputDir() + File.separator + "scenario.sh";
+ try (FileWriter writer = new FileWriter(new File(scriptPath))) {
+ cfg.getTemplate("scenario.sh")
+ .process(root, writer);
+ } catch (Exception e) {
+ LOGGER.error("Failed to write scenario.sh", e);
+ }
+ }
+
+ public abstract void generateAdditionFiles(IConfiguration configuration) throws GenerateFailedException;
+
+ public abstract String runningScript(IConfiguration configuration);
+}
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
new file mode 100644
index 0000000..c0a2e6e
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
@@ -0,0 +1,547 @@
+/*
+ * 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.apache.dubbo.scenario.builder.exception.ConfigureFileNotFoundException;
+import org.apache.dubbo.scenario.builder.vo.CaseConfiguration;
+import org.apache.dubbo.scenario.builder.vo.DockerService;
+import org.apache.dubbo.scenario.builder.vo.ServiceComponent;
+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.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ConfigurationImpl implements IConfiguration {
+ public static final String SAMPLE_TEST_IMAGE = "dubbo/sample-test";
+ public static final String DUBBO_APP_DIR = "/usr/local/dubbo/app";
+ public static final String DUBBO_LOG_DIR = "/usr/local/dubbo/logs";
+ public static final String ENV_SERVICE_NAME = "SERVICE_NAME";
+ public static final String ENV_SERVICE_TYPE = "SERVICE_TYPE";
+ public static final String ENV_APP_MAIN_CLASS = "APP_MAIN_CLASS";
+ public static final String ENV_WAIT_PORTS_BEFORE_RUN = "WAIT_PORTS_BEFORE_RUN";
+ public static final String ENV_CHECK_PORTS_AFTER_RUN = "CHECK_PORTS_AFTER_RUN";
+ public static final String ENV_CHECK_LOG = "CHECK_LOG";
+ public static final String ENV_CHECK_TIMEOUT = "CHECK_TIMEOUT";
+ public static final String ENV_TEST_PATTERNS = "TEST_PATTERNS";
+ public static final String ENV_JAVA_OPTS = "JAVA_OPTS";
+ public static final String ENV_SCENARIO_HOME = "SCENARIO_HOME";
+
+ private static final Logger logger = LoggerFactory.getLogger(ConfigurationImpl.class);
+ private final CaseConfiguration configuration;
+ private String scenarioHome;
+ private String configBasedir;
+ private String scenarioName;
+ private final String scenarioLogDir;
+ private int scenarioTimeout = 90;
+ private int javaDebugPort=20660;
+ private int debugTimeout=36000;
+ private String debugSuspend="y";
+
+ public ConfigurationImpl() throws IOException, ConfigureFileNotFoundException {
+ String configureFile = System.getProperty("configure.file");
+ if (StringUtils.isBlank(configureFile)) {
+ throw new ConfigureFileNotFoundException();
+ }
+ this.configBasedir = new File(configureFile).getParentFile().getCanonicalPath();
+
+ //set default scenarioHome dir to ${configBasedir}/target
+ this.scenarioHome = System.getProperty("scenario.home");
+ if (StringUtils.isBlank(scenarioHome)) {
+ scenarioHome = configBasedir + "/target";
+ }
+ scenarioLogDir = new File(scenarioHome, "logs").getCanonicalPath();
+
+ //set default scenarioName
+ scenarioName = System.getProperty("scenario.name");
+ if (StringUtils.isBlank(scenarioName)) {
+ scenarioName = new File(configBasedir).getName();
+ }
+
+ this.configuration = loadCaseConfiguration(configureFile);
+ if (this.configuration.getTimeout() > 0) {
+ scenarioTimeout = this.configuration.getTimeout();
+ }
+ String timeout = System.getProperty("timeout");
+ if (StringUtils.isNotBlank(timeout)) {
+ scenarioTimeout = Integer.parseInt(timeout);
+ }
+ if (isDebug()) {
+ scenarioTimeout=debugTimeout;
+ debugSuspend=System.getProperty("debug.suspend", debugSuspend);
+ }
+ }
+
+ private CaseConfiguration loadCaseConfiguration(String configureFile) throws IOException {
+ // read 'props'
+ String configYaml = readFully(configureFile);
+ CaseConfiguration tmpConfiguration = parseConfiguration(configYaml);
+ Map<String, String> props = tmpConfiguration.getProps();
+
+ // process 'from', load parent config
+ CaseConfiguration parentConfiguration = null;
+ if (StringUtils.isNotBlank(tmpConfiguration.getFrom())) {
+ String parentConfigYaml = loadParentConfigYaml(tmpConfiguration);
+ CaseConfiguration tmpParentConfiguration = parseConfiguration(parentConfigYaml);
+
+ //merge props, overwrite parent props
+ Map<String, String> newProps = new HashMap<>(tmpParentConfiguration.getProps());
+ newProps.putAll(props);
+ props = newProps;
+
+ // replace variables '${...}'
+ String newParentConfigYaml = replaceHolders(parentConfigYaml, props);
+ parentConfiguration = parseConfiguration(newParentConfigYaml);
+ }
+
+ // replace variables '${...}'
+ String newConfigYaml = replaceHolders(configYaml, props);
+ CaseConfiguration caseConfiguration = parseConfiguration(newConfigYaml);
+
+ //merge globalSystemProps, overwrite parent
+ if (parentConfiguration != null) {
+ List<String> systemProps = mergeSystemProps(parentConfiguration.getSystemProps(), caseConfiguration.getSystemProps());
+ caseConfiguration.setSystemProps(systemProps);
+ }
+
+ //merge services
+ if (parentConfiguration != null && parentConfiguration.getServices() != null) {
+ Map<String, ServiceComponent> newServices = new LinkedHashMap<>(parentConfiguration.getServices());
+ if (caseConfiguration.getServices() != null) {
+ newServices.putAll(caseConfiguration.getServices());
+ }
+ caseConfiguration.setServices(newServices);
+ }
+
+ fillupServices(caseConfiguration);
+ return caseConfiguration;
+ }
+
+ private List<String> mergeSystemProps(List<String> parentSystemProps, List<String> childSystemProps) {
+ List<String> newSystemProps = new ArrayList<>(parentSystemProps != null ? parentSystemProps : Collections.emptyList());
+ if (childSystemProps != null) {
+ childSystemProps.forEach(entry -> {
+ String[] strs = entry.split("=");
+ addOrReplaceKVEntry(newSystemProps, strs[0].trim(), strs.length > 1 ? strs[1].trim() : "");
+ });
+ }
+ return newSystemProps;
+ }
+
+ private String loadParentConfigYaml(CaseConfiguration caseConfiguration) throws IOException {
+ try {
+ String file = "configs/" + caseConfiguration.getFrom();
+ InputStream inputStream = CaseConfiguration.class.getClassLoader().getResourceAsStream(file);
+ return readFully(inputStream);
+ } catch (Exception e) {
+ logger.error("load parent config failed: " + caseConfiguration.getFrom(), e);
+ throw new IOException("load parent config failed: " + caseConfiguration.getFrom(), e);
+ }
+ }
+
+ private CaseConfiguration parseConfiguration(String configYaml) {
+ return new Yaml().loadAs(configYaml, CaseConfiguration.class);
+ }
+
+ private void fillupServices(CaseConfiguration caseConfiguration) throws IOException {
+ List<String> caseSystemProps = caseConfiguration.getSystemProps();
+ for (Map.Entry<String, ServiceComponent> entry : caseConfiguration.getServices().entrySet()) {
+ String serviceName = entry.getKey();
+ ServiceComponent service = entry.getValue();
+ String type = service.getType();
+ if (isAppService(type)) {
+ service.setImage(SAMPLE_TEST_IMAGE);
+ service.setBasedir(toAbsolutePath(service.getBasedir()));
+ if (service.getVolumes() == null) {
+ service.setVolumes(new ArrayList<>());
+ }
+ //mount ${project.basedir}/target : DUBBO_APP_DIR
+ String targetPath = new File(service.getBasedir(), "target").getCanonicalPath();
+ service.getVolumes().add(targetPath + ":" + DUBBO_APP_DIR);
+
+ //mount ${scenario_home}/logs : DUBBO_LOG_DIR
+ service.getVolumes().add(scenarioLogDir + ":" + DUBBO_LOG_DIR);
+
+ if (service.getEnvironment() == null) {
+ service.setEnvironment(new ArrayList<>());
+ }
+ // set service name
+ setEnv(service, ENV_SERVICE_NAME, serviceName);
+
+ //set wait ports
+ if (isNotEmpty(service.getWaitPortsBeforeRun())) {
+ String str = convertAddrPortsToString(service.getWaitPortsBeforeRun());
+ setEnv(service, ENV_WAIT_PORTS_BEFORE_RUN, str);
+ }
+
+ //set check timeout
+ if (isDebug()) {
+ service.setCheckTimeout(debugTimeout);
+
+ //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=%s,address=%s", debugSuspend, debugPort);
+ appendEnv(service, ENV_JAVA_OPTS, debugOpts);
+
+ //mapping debug port
+ if (service.getPorts() == null) {
+ service.setPorts(new ArrayList<>());
+ }
+ service.getPorts().add(debugPort + ":" + debugPort);
+ }
+ if (service.getCheckTimeout() > 0) {
+ setEnv(service, ENV_CHECK_TIMEOUT, service.getCheckTimeout()+"");
+ }
+
+ if ("app".equals(type)) {
+ String mainClass = service.getMainClass();
+ if (StringUtils.isBlank(mainClass)) {
+ throw new RuntimeException("Missing 'mainClass' for app service [" + serviceName + "]");
+ }
+ //set SERVICE_TYPE
+ setEnv(service, ENV_SERVICE_TYPE, type);
+ //set mainClass env
+ setEnv(service, ENV_APP_MAIN_CLASS, mainClass);
+ //set SCENARIO_HOME
+ setEnv(service, ENV_SCENARIO_HOME, scenarioHome);
+
+ //set check_log env
+ if (StringUtils.isNotBlank(service.getCheckLog())) {
+ setEnv(service, ENV_CHECK_LOG, service.getCheckLog());
+ }
+
+ //set check ports
+ if (isNotEmpty(service.getCheckPortsAfterRun())) {
+ String str = convertAddrPortsToString(service.getCheckPortsAfterRun());
+ setEnv(service, ENV_CHECK_PORTS_AFTER_RUN, str);
+ }
+ } else if ("test".equals(type)) {
+ String mainClass = service.getMainClass();
+ if (StringUtils.isNotBlank(mainClass)) {
+ throw new RuntimeException("Illegal attribute 'mainClass' for test service [" + serviceName + "]");
+ }
+ //set SERVICE_TYPE
+ setEnv(service, ENV_SERVICE_TYPE, type);
+
+ //set TEST_PATTERNS
+ if (isNotEmpty(service.getTests())) {
+ String str = StringUtils.join(service.getTests(), ';');
+ setEnv(service, ENV_TEST_PATTERNS, str);
+ }
+ } else {
+ throw new RuntimeException("Illegal service type: " + type);
+ }
+ }
+
+ // set hostname to serviceId if absent
+ if (StringUtils.isBlank(service.getHostname())) {
+ service.setHostname(serviceName);
+ }
+
+ //set jvmFlags
+ if (isNotEmpty(service.getJvmFlags())) {
+ String str = StringUtils.join(service.getJvmFlags(), ' ');
+ appendEnv(service, ENV_JAVA_OPTS, str);
+ }
+
+ //set systemProps
+ List<String> systemProps = mergeSystemProps(caseSystemProps, service.getSystemProps());
+ if (isNotEmpty(systemProps)) {
+ String str = convertSystemPropsToJvmFlags(systemProps);
+ appendEnv(service, ENV_JAVA_OPTS, str);
+ }
+
+ }
+ }
+
+ private void appendEnv(ServiceComponent service, String name, String value) {
+ String prefix = name + "=";
+ List<String> environments = service.getEnvironment();
+ if (environments == null) {
+ environments = new ArrayList<>();
+ service.setEnvironment(environments);
+ }
+ for (int i = 0; i < environments.size(); i++) {
+ String env = environments.get(i);
+ if (env.startsWith(prefix)) {
+ // append to exist env
+ env += " " + value;
+ environments.set(i, env);
+ return;
+ }
+ }
+ environments.add(name + "=" + value);
+ }
+
+ private void setEnv(ServiceComponent service, String name, String value) {
+ List<String> environments = service.getEnvironment();
+ addOrReplaceKVEntry(environments, name, value);
+ }
+
+ private void addOrReplaceKVEntry(List<String> map, String name, String value) {
+ String prefix = name + "=";
+ for (int i = 0; i < map.size(); i++) {
+ String env = map.get(i);
+ if (env.startsWith(prefix)) {
+ //replace old env
+ env = name + "=" + value;
+ map.set(i, env);
+ return;
+ }
+ }
+ map.add(name + "=" + value);
+ }
+
+ //convert systemProp key=value to -Dkey=value
+ private String convertSystemPropsToJvmFlags(List<String> systemProps) {
+ StringBuilder sb = new StringBuilder();
+ for (String propkv : systemProps) {
+ sb.append("-D").append(propkv).append(' ');
+ }
+ return sb.toString();
+ }
+
+ private boolean isNotEmpty(List<String> list) {
+ return list != null && list.size() > 0;
+ }
+
+ private String convertAddrPortsToString(List<String> addrPorts) {
+ StringBuilder sb = new StringBuilder();
+ for (String addrPort : addrPorts) {
+ if (!addrPort.contains(":")) {
+ addrPort = "127.0.0.1" + ":" + addrPort;
+ }
+ sb.append(addrPort).append(";");
+ }
+ return sb.toString();
+ }
+
+ private String toAbsolutePath(String path) throws IOException {
+ File file = new File(path);
+ if (file.isAbsolute()) {
+ return file.getCanonicalPath();
+ }
+ //relative path to basedir of configuration file
+ return new File(configBasedir, path).getCanonicalPath();
+ }
+
+ private boolean isAppService(String type) {
+ if (type == null) {
+ return false;
+ }
+ switch (type) {
+ case "app":
+ case "test":
+ return true;
+ }
+ 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) {
+ StringBuffer buf = new StringBuffer(str.length());
+ Matcher matcher = pattern.matcher(str);
+ while (matcher.find()) {
+ String var = matcher.group(1);
+ String value = props.get(var);
+ matcher.appendReplacement(buf, value != null ? value : matcher.group());
+ }
+ matcher.appendTail(buf);
+ return buf.toString();
+ }
+
+ @Override
+ public ScenarioRunningScriptGenerator scenarioGenerator() {
+ return new DockerComposeRunningGenerator();
+ }
+
+ @Override
+ public CaseConfiguration caseConfiguration() {
+ return this.configuration;
+ }
+
+ @Override
+ public String scenarioName() {
+ return scenarioName;
+ }
+
+ @Override
+ public String scenarioVersion() {
+ return System.getProperty("scenario.version");
+ }
+
+ @Override
+ public String dockerImageVersion() {
+ return System.getProperty("docker.image.version", "latest");
+ }
+
+ @Override
+ public String dockerNetworkName() {
+ return (scenarioName() + "-" + dockerImageVersion()).toLowerCase();
+ }
+
+ @Override
+ public String dockerContainerName() {
+ return (scenarioName() + "-" + scenarioVersion() + "-" + dockerImageVersion()).toLowerCase();
+ }
+
+ @Override
+ public String scenarioHome() {
+ return this.scenarioHome;
+ }
+
+ @Override
+ public String outputDir() {
+ return scenarioHome;
+ }
+
+ @Override
+ public String jacocoHome() {
+ return System.getProperty("jacoco.home");
+ }
+
+ @Override
+ public String debugMode() {
+ return System.getProperty("debug.mode", "0");
+ }
+
+ private boolean isDebug() {
+ return "1".equals(debugMode());
+ }
+
+ private int nextDebugPort() {
+ return javaDebugPort++;
+ }
+
+ @Override
+ public Map<String, Object> toMap() {
+ CaseConfiguration caseConfiguration = caseConfiguration();
+ final Map<String, Object> root = new HashMap<>();
+
+ root.put("scenario_home", scenarioHome());
+ root.put("scenario_name", scenarioName());
+ root.put("scenario_version", scenarioVersion());
+ root.put("docker_container_name", dockerContainerName());
+ root.put("jacoco_home", jacocoHome());
+ root.put("debug_mode", debugMode());
+ root.put("docker_compose_file", outputDir() + File.separator + "docker-compose.yml");
+ root.put("network_name", dockerNetworkName());
+ root.put("timeout", scenarioTimeout);
+
+ final StringBuilder removeImagesScript = new StringBuilder();
+ List<String> links = new ArrayList<>();
+ if (caseConfiguration.getServices() != null) {
+ caseConfiguration.getServices().forEach((name, service) -> {
+ links.add(service.getHostname());
+ if (service.isRemoveOnExit()) {
+ removeImagesScript.append("docker rmi ")
+ .append(service.getImage())
+ .append(System.lineSeparator());
+ }
+ });
+ }
+ root.put("removeImagesScript", removeImagesScript.toString());
+
+// add links to test service
+// caseConfiguration.getServices().forEach((name, service) -> {
+// if ("test".equals(service.getType())) {
+// if (service.getLinks() == null) {
+// service.setLinks(new ArrayList<>());
+// }
+// for (String link : links) {
+// if (!StringUtils.equals(link, service.getHostname())) {
+// service.getLinks().add(link);
+// }
+// }
+// }
+// });
+
+ root.put("services", convertDockerServices(scenarioVersion(), caseConfiguration.getServices()));
+ List<String> testServiceNames = findTestServiceNames(caseConfiguration);
+ root.put("test_service_name", testServiceNames.size() > 0 ? testServiceNames.get(0) : "");
+
+ return root;
+ }
+
+ private List<String> findTestServiceNames(CaseConfiguration caseConfiguration) {
+ List<String> serviceNames = new ArrayList<>();
+ for (Map.Entry<String, ServiceComponent> entry : caseConfiguration.getServices().entrySet()) {
+ ServiceComponent service = entry.getValue();
+ if ("test".equals(service.getType())) {
+ serviceNames.add(entry.getKey());
+ }
+ }
+ return serviceNames;
+ }
+
+ protected List<DockerService> convertDockerServices(final String version,
+ Map<String, ServiceComponent> componentMap) {
+ final ArrayList<DockerService> services = new ArrayList<>();
+ if (componentMap == null) {
+ return services;
+ }
+ componentMap.forEach((name, dependency) -> {
+ DockerService service = new DockerService();
+
+ String imageName = dependency.getImage();
+ service.setName(name);
+ service.setImageName(imageName);
+ service.setHostname(dependency.getHostname());
+ service.setExpose(dependency.getExpose());
+ service.setPorts(dependency.getPorts());
+ service.setDepends_on(dependency.getDepends_on());
+ service.setLinks(dependency.getDepends_on());
+ service.setEntrypoint(dependency.getEntrypoint());
+ service.setHealthcheck(dependency.getHealthcheck());
+ service.setEnvironment(dependency.getEnvironment());
+ service.setVolumes(dependency.getVolumes());
+ service.setRemoveOnExit(dependency.isRemoveOnExit());
+ services.add(service);
+ });
+ return services;
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/DockerComposeRunningGenerator.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/DockerComposeRunningGenerator.java
new file mode 100644
index 0000000..b7e17a5
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/DockerComposeRunningGenerator.java
@@ -0,0 +1,75 @@
+/*
+ * 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 freemarker.template.Configuration;
+import freemarker.template.TemplateException;
+import freemarker.template.TemplateExceptionHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.lang.invoke.MethodHandles;
+import java.util.Map;
+
+public class DockerComposeRunningGenerator extends AbstractRunningGenerator {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ protected DockerComposeRunningGenerator() {
+ }
+
+ @Override
+ public void generateAdditionFiles(IConfiguration configuration) {
+ final Map<String, Object> root = configuration.toMap();
+
+ Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
+ try {
+ cfg.setClassLoaderForTemplateLoading(this.getClass().getClassLoader(), "/");
+ cfg.setDefaultEncoding("UTF-8");
+ cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
+ cfg.setLogTemplateExceptions(false);
+ cfg.setWrapUncheckedExceptions(true);
+ cfg.setNumberFormat("computer");
+ } catch (Exception e) {
+ // never to do this
+ }
+ try {
+ cfg.getTemplate("docker-compose.template")
+ .process(root, new FileWriter(new File(configuration.outputDir(), "docker-compose.yml")));
+ } catch (TemplateException | IOException e) {
+ LOGGER.error("", e);
+ }
+ }
+
+ @Override
+ public String runningScript(IConfiguration configuration) {
+ final Map<String, Object> root = configuration.toMap();
+
+ StringWriter out = new StringWriter();
+
+ try {
+ cfg.getTemplate("compose-start-script.template").process(root, out);
+ } catch (Exception e) {
+ LOGGER.error("Failed to generate running script.", e);
+ }
+ return out.toString();
+ }
+}
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
new file mode 100644
index 0000000..6b19381
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/IConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * 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.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();
+
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java
new file mode 100644
index 0000000..62be59b
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioBuilderMain.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+public class ScenarioBuilderMain {
+
+ public static void main(String[] args) throws Exception {
+ IConfiguration configuration = new ConfigurationImpl();
+ configuration.scenarioGenerator().generate(configuration);
+ System.out.println("outputDir: " + configuration.outputDir());
+ System.exit(0);
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioRunningScriptGenerator.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioRunningScriptGenerator.java
new file mode 100644
index 0000000..d824e32
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ScenarioRunningScriptGenerator.java
@@ -0,0 +1,25 @@
+/*
+ * 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.dubbo.scenario.builder.exception.GenerateFailedException;
+
+public interface ScenarioRunningScriptGenerator {
+ void generate(IConfiguration configuration) throws GenerateFailedException;
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/exception/ConfigureFileNotFoundException.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/exception/ConfigureFileNotFoundException.java
new file mode 100644
index 0000000..156bded
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/exception/ConfigureFileNotFoundException.java
@@ -0,0 +1,23 @@
+/*
+ * 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.exception;
+
+public class ConfigureFileNotFoundException extends Exception {
+ public ConfigureFileNotFoundException() {
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/exception/GenerateFailedException.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/exception/GenerateFailedException.java
new file mode 100644
index 0000000..4c141c2
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/exception/GenerateFailedException.java
@@ -0,0 +1,21 @@
+/*
+ * 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.exception;
+
+public class GenerateFailedException extends Exception {
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/CaseConfiguration.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/CaseConfiguration.java
new file mode 100644
index 0000000..6401dec
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/CaseConfiguration.java
@@ -0,0 +1,70 @@
+/*
+ * 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.vo;
+
+
+import java.util.List;
+import java.util.Map;
+
+public class CaseConfiguration {
+ private String from;
+ private Map<String, String> props;
+ private List<String> systemProps;
+ private Map<String, ServiceComponent> services;
+ private int timeout;
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public Map<String, ServiceComponent> getServices() {
+ return services;
+ }
+
+ public void setServices(Map<String, ServiceComponent> services) {
+ this.services = services;
+ }
+
+ public Map<String, String> getProps() {
+ return props;
+ }
+
+ public void setProps(Map<String, String> props) {
+ this.props = props;
+ }
+
+ public List<String> getSystemProps() {
+ return systemProps;
+ }
+
+ public void setSystemProps(List<String> systemProps) {
+ this.systemProps = systemProps;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/DockerService.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/DockerService.java
new file mode 100644
index 0000000..4737d19
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/DockerService.java
@@ -0,0 +1,131 @@
+/*
+ * 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.vo;
+
+import java.util.List;
+
+public class DockerService {
+ private String name;
+ private String imageName;
+ private String hostname;
+ private boolean removeOnExit;
+ private List<String> links;
+ private List<String> expose;
+ private List<String> ports;
+ private List<String> entrypoint;
+ private List<String> healthcheck;
+ private List<String> depends_on;
+ private List<String> environment;
+ private List<String> volumes;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getImageName() {
+ return imageName;
+ }
+
+ public void setImageName(String imageName) {
+ this.imageName = imageName;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public boolean isRemoveOnExit() {
+ return removeOnExit;
+ }
+
+ public void setRemoveOnExit(boolean removeOnExit) {
+ this.removeOnExit = removeOnExit;
+ }
+
+ public List<String> getLinks() {
+ return links;
+ }
+
+ public void setLinks(List<String> links) {
+ this.links = links;
+ }
+
+ public List<String> getExpose() {
+ return expose;
+ }
+
+ public void setExpose(List<String> expose) {
+ this.expose = expose;
+ }
+
+ public List<String> getEntrypoint() {
+ return entrypoint;
+ }
+
+ public void setEntrypoint(List<String> entrypoint) {
+ this.entrypoint = entrypoint;
+ }
+
+ public List<String> getHealthcheck() {
+ return healthcheck;
+ }
+
+ public void setHealthcheck(List<String> healthcheck) {
+ this.healthcheck = healthcheck;
+ }
+
+ public List<String> getDepends_on() {
+ return depends_on;
+ }
+
+ public void setDepends_on(List<String> depends_on) {
+ this.depends_on = depends_on;
+ }
+
+ public List<String> getEnvironment() {
+ return environment;
+ }
+
+ public void setEnvironment(List<String> environment) {
+ this.environment = environment;
+ }
+
+ public List<String> getVolumes() {
+ return volumes;
+ }
+
+ public void setVolumes(List<String> volumes) {
+ this.volumes = volumes;
+ }
+
+ public List<String> getPorts() {
+ return ports;
+ }
+
+ public void setPorts(List<String> ports) {
+ this.ports = ports;
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/JavaDebugOption.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/JavaDebugOption.java
new file mode 100644
index 0000000..107aa92
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/JavaDebugOption.java
@@ -0,0 +1,40 @@
+/*
+ * 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.vo;
+
+public class JavaDebugOption {
+
+ private int port;
+ private String suspend;
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getSuspend() {
+ return suspend;
+ }
+
+ public void setSuspend(String suspend) {
+ this.suspend = suspend;
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/ServiceComponent.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/ServiceComponent.java
new file mode 100644
index 0000000..c7fd2d6
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/vo/ServiceComponent.java
@@ -0,0 +1,242 @@
+/*
+ * 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.vo;
+
+
+import java.util.List;
+
+public class ServiceComponent {
+ private String image;
+ private String hostname;
+ private String version;
+ private boolean removeOnExit = false;
+ private List<String> links;
+ private List<String> expose;
+ private List<String> ports;
+ private List<String> entrypoint;
+ private List<String> environment;
+ private List<String> volumes;
+ private List<String> volumes_from;
+ private List<String> depends_on;
+ private List<String> healthcheck;
+
+ // app attrs
+ private String type;
+ private String basedir;
+ private String mainClass;
+ private List<String> waitPortsBeforeRun;
+ private List<String> checkPortsAfterRun;
+ private String checkLog;
+ private int checkTimeout;
+ private List<String> tests;
+ private List<String> systemProps;
+ private List<String> jvmFlags;
+ private JavaDebugOption javaDebug;
+
+ public String getImage() {
+ return image;
+ }
+
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public boolean isRemoveOnExit() {
+ return removeOnExit;
+ }
+
+ public void setRemoveOnExit(boolean removeOnExit) {
+ this.removeOnExit = removeOnExit;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public List<String> getLinks() {
+ return links;
+ }
+
+ public void setLinks(List<String> links) {
+ this.links = links;
+ }
+
+ public List<String> getExpose() {
+ return expose;
+ }
+
+ public void setExpose(List<String> expose) {
+ this.expose = expose;
+ }
+
+ public List<String> getEntrypoint() {
+ return entrypoint;
+ }
+
+ public void setEntrypoint(List<String> entrypoint) {
+ this.entrypoint = entrypoint;
+ }
+
+ public List<String> getEnvironment() {
+ return environment;
+ }
+
+ public void setEnvironment(List<String> environment) {
+ this.environment = environment;
+ }
+
+ public List<String> getDepends_on() {
+ return depends_on;
+ }
+
+ public void setDepends_on(List<String> depends_on) {
+ this.depends_on = depends_on;
+ }
+
+ public List<String> getHealthcheck() {
+ return healthcheck;
+ }
+
+ public void setHealthcheck(List<String> healthcheck) {
+ this.healthcheck = healthcheck;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getBasedir() {
+ return basedir;
+ }
+
+ public void setBasedir(String basedir) {
+ this.basedir = basedir;
+ }
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ public void setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ public List<String> getCheckPortsAfterRun() {
+ return checkPortsAfterRun;
+ }
+
+ public void setCheckPortsAfterRun(List<String> checkPortsAfterRun) {
+ this.checkPortsAfterRun = checkPortsAfterRun;
+ }
+
+ public List<String> getWaitPortsBeforeRun() {
+ return waitPortsBeforeRun;
+ }
+
+ public void setWaitPortsBeforeRun(List<String> waitPortsBeforeRun) {
+ this.waitPortsBeforeRun = waitPortsBeforeRun;
+ }
+
+ public String getCheckLog() {
+ return checkLog;
+ }
+
+ public void setCheckLog(String checkLog) {
+ this.checkLog = checkLog;
+ }
+
+ public int getCheckTimeout() {
+ return checkTimeout;
+ }
+
+ public void setCheckTimeout(int checkTimeout) {
+ this.checkTimeout = checkTimeout;
+ }
+
+ public List<String> getTests() {
+ return tests;
+ }
+
+ public void setTests(List<String> tests) {
+ this.tests = tests;
+ }
+
+ public List<String> getSystemProps() {
+ return systemProps;
+ }
+
+ public void setSystemProps(List<String> systemProps) {
+ this.systemProps = systemProps;
+ }
+
+ public List<String> getJvmFlags() {
+ return jvmFlags;
+ }
+
+ public void setJvmFlags(List<String> jvmFlags) {
+ this.jvmFlags = jvmFlags;
+ }
+
+ public List<String> getVolumes() {
+ return volumes;
+ }
+
+ public void setVolumes(List<String> volumes) {
+ this.volumes = volumes;
+ }
+
+ public List<String> getVolumes_from() {
+ return volumes_from;
+ }
+
+ public void setVolumes_from(List<String> volumes_from) {
+ this.volumes_from = volumes_from;
+ }
+
+ public JavaDebugOption getJavaDebug() {
+ return javaDebug;
+ }
+
+ public void setJavaDebug(JavaDebugOption javaDebug) {
+ this.javaDebug = javaDebug;
+ }
+
+ public List<String> getPorts() {
+ return ports;
+ }
+
+ public void setPorts(List<String> ports) {
+ this.ports = ports;
+ }
+}
diff --git a/test/dubbo-scenario-builder/src/main/resources/compose-start-script.template b/test/dubbo-scenario-builder/src/main/resources/compose-start-script.template
new file mode 100644
index 0000000..6c438b5
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/resources/compose-start-script.template
@@ -0,0 +1,18 @@
+<#--
+ ~ 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.
+-->
+
+
diff --git a/test/dubbo-scenario-builder/src/main/resources/configs/app-builtin-zookeeper.yml b/test/dubbo-scenario-builder/src/main/resources/configs/app-builtin-zookeeper.yml
new file mode 100644
index 0000000..436df2f
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/resources/configs/app-builtin-zookeeper.yml
@@ -0,0 +1,57 @@
+# 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.
+
+# example:
+
+#from: app-builtin-zookeeper.yml
+#props:
+# project_name: dubbo-samples-annotation
+# main_class: org.apache.dubbo.samples.annotation.AnnotationProviderBootstrap
+# zookeeper_port: 2181
+# dubbo_port: 20880
+
+
+props:
+# project_name: dubbo-samples-xxx
+# main_class: org.apache.dubbo.samples.xxx.XxxProviderBootstrap
+ zookeeper_port: 2181
+ dubbo_port: 20880
+
+services:
+ ${project_name}:
+ type: app
+ basedir: .
+ mainClass: ${main_class}
+# checkPortsAfterRun:
+# - ${zookeeper_port}
+# - ${dubbo_port}
+# checkLog: "dubbo service started"
+
+ ${project_name}-test:
+ type: test
+ basedir: .
+ tests:
+ - "**/*IT.class"
+ systemProps:
+ - zookeeper.address=${project_name}
+ - zookeeper.port=${zookeeper_port}
+ - dubbo.address=${project_name}
+ - dubbo.port=${dubbo_port}
+ waitPortsBeforeRun:
+ - ${project_name}:${zookeeper_port}
+ - ${project_name}:${dubbo_port}
+ depends_on:
+ - ${project_name}
diff --git a/test/dubbo-scenario-builder/src/main/resources/configs/app-external-zookeeper.yml b/test/dubbo-scenario-builder/src/main/resources/configs/app-external-zookeeper.yml
new file mode 100644
index 0000000..6031fe2
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/resources/configs/app-external-zookeeper.yml
@@ -0,0 +1,64 @@
+# 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.
+
+# example:
+
+#from: app-external-zookeeper.yml
+#props:
+# project_name: dubbo-samples-annotation
+# main_class: org.apache.dubbo.samples.annotation.AnnotationProviderBootstrap
+# dubbo_port: 20880
+# zookeeper_version: latest
+
+
+props:
+# project_name: dubbo-samples-xxx
+# main_class: org.apache.dubbo.samples.xxx.XxxProviderBootstrap
+ dubbo_port: 20880
+ zookeeper_version: latest
+
+services:
+ zookeeper:
+ image: zookeeper:${zookeeper_version}
+
+ ${project_name}:
+ type: app
+ basedir: .
+ mainClass: ${main_class}
+ systemProps:
+ - zookeeper.address=zookeeper
+ - zookeeper.port=2181
+ waitPortsBeforeRun:
+ - zookeeper:2181
+# checkPortsAfterRun:
+# - ${dubbo_port}
+# checkLog: "dubbo service started"
+
+ ${project_name}-test:
+ type: test
+ basedir: .
+ tests:
+ - "**/*IT.class"
+ systemProps:
+ - zookeeper.address=zookeeper
+ - zookeeper.port=2181
+ - dubbo.address=${project_name}
+ - dubbo.port=${dubbo_port}
+ waitPortsBeforeRun:
+ - zookeeper:2181
+ - ${project_name}:${dubbo_port}
+ depends_on:
+ - ${project_name}
diff --git a/test/dubbo-scenario-builder/src/main/resources/docker-compose.template b/test/dubbo-scenario-builder/src/main/resources/docker-compose.template
new file mode 100644
index 0000000..1211966
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/resources/docker-compose.template
@@ -0,0 +1,88 @@
+<#--
+ ~ 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.
+-->
+version: '2.1'
+
+networks:
+ default:
+ name: ${network_name}
+
+services:
+<#list services as service>
+ ${service.name}:
+ image: ${service.imageName}
+ hostname: ${service.hostname}
+ <#if service.volumes??>
+ volumes:
+ <#list service.volumes as volume>
+ - ${volume}
+ </#list>
+ </#if>
+ <#if service.volumes_from??>
+ volumes_from:
+ <#list service.volumes_from as volume>
+ - ${volume}
+ </#list>
+ </#if>
+ <#if service.environment??>
+ environment:
+ <#list service.environment as environment>
+ - ${environment}
+ </#list>
+ </#if>
+ <#if service.expose??>
+ expose:
+ <#list service.expose as expose>
+ - ${expose}
+ </#list>
+ </#if>
+ <#if service.ports??>
+ ports:
+ <#list service.ports as port>
+ - ${port}
+ </#list>
+ </#if>
+ <#if service.startScript??>
+ command:
+ <#list service.startScript as startScript>
+ - ${startScript}
+ </#list>
+ </#if>
+ <#if service.depends_on??>
+ depends_on:
+ <#list service.depends_on as item>
+ - ${item}
+ </#list>
+ </#if>
+ <#if service.entrypoint??>
+ entrypoint:
+ <#list service.entrypoint as item>
+ - ${item}
+ </#list>
+ </#if>
+ <#if service.healthcheck??>
+ healthcheck:
+ <#list service.healthcheck as item>
+ ${item}
+ </#list>
+ </#if>
+ <#if service.links??>
+ links:
+ <#list service.links as item>
+ - ${item}
+ </#list>
+ </#if>
+</#list>
diff --git a/test/dubbo-scenario-builder/src/main/resources/scenario.sh b/test/dubbo-scenario-builder/src/main/resources/scenario.sh
new file mode 100644
index 0000000..29ae046
--- /dev/null
+++ b/test/dubbo-scenario-builder/src/main/resources/scenario.sh
@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+
+# 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.
+
+PRG="$0"
+PRGDIR=`dirname "$PRG"`
+[ -z "$SCENARIO_HOME" ] && SCENARIO_HOME=`cd "$PRGDIR" >/dev/null; pwd`
+cd $SCENARIO_HOME
+
+# set vars from freemarker
+testcase_name=${scenario_name}-${scenario_version}
+config_debug_mode=${debug_mode}
+config_timeout=${timeout}
+scenario_name=${scenario_name}
+compose_file="${docker_compose_file}"
+project_name=$(echo "${scenario_name}_${scenario_version}" |sed -e "s/\.//g" |awk '{print tolower($0)}')
+test_service_name="${test_service_name}_1"
+network_name="${network_name}"
+
+<#noparse>
+status=1
+start=$SECONDS
+
+mkdir -p ${SCENARIO_HOME}/logs
+scenario_log=${SCENARIO_HOME}/logs/scenario.log
+rm -f $scenario_log
+
+# overrite configs
+debug_mode=${debug_mode:-$config_debug_mode}
+timeout=${timeout:-$config_timeout}
+echo "[$scenario_name] debug_mode: $debug_mode" >> $scenario_log
+echo "[$scenario_name] timeout: $timeout" >> $scenario_log
+
+function wait_container_exit() {
+ container_name=$1
+ start=$2
+ timeout=$3
+
+ # check and get exit code
+ while [ 1 = 1 ];
+ do
+ status=`docker inspect $container_name --format='{{.State.Status}}'`
+ result=$?
+ if [ $result -ne 0 ];then
+ echo "check container status failure: $result"
+ return 1
+ fi
+ if [ "$status" == "exited" ];then
+ return 0
+ fi
+
+ duration=$(( SECONDS - start ))
+ if [ $duration -gt $timeout ];then
+ echo "wait for container is timeout: $duration s"
+ return 1
+ fi
+ sleep 2
+ done
+}
+
+#Starting test containers
+container_name="${project_name}_${test_service_name}"
+
+#kill and clean first
+echo "[$scenario_name] Killing test containers .." | tee -a $scenario_log
+docker-compose -p ${project_name} -f ${compose_file} kill 2>&1 | tee -a $scenario_log > /dev/null
+
+echo "[$scenario_name] Removing test containers .." | tee -a $scenario_log
+docker-compose -p ${project_name} -f ${compose_file} rm -f 2>&1 | tee -a $scenario_log > /dev/null
+
+# complete pull fail interactive by <<< "NN"
+echo "[$scenario_name] Starting test containers .." | tee -a $scenario_log
+docker-compose -p ${project_name} -f ${compose_file} up -d --no-build 2>&1 <<< "NN" | tee -a $scenario_log > /dev/null
+
+container_id=`docker ps -qf "name=${container_name}"`
+if [[ -z "${container_id}" ]]; then
+ echo "[$scenario_name] docker startup failure!" | tee -a $scenario_log
+ status=1
+else
+ # check and get exit code
+ wait_container_exit ${container_name} $start $timeout
+ result=$?
+ if [ $result -eq 0 ]; then
+ result=`docker inspect ${container_name} --format='{{.State.ExitCode}}'`
+ if [ $result -eq 0 ]; then
+ status=0
+ echo "[$scenario_name] Run tests successfully" | tee -a $scenario_log
+ else
+ status=$result
+ echo "[$scenario_name] Run tests failed" | tee -a $scenario_log
+ fi
+ else
+ status=1
+ echo "[$scenario_name] Run tests timeout" | tee -a $scenario_log
+ fi
+
+ echo "[$scenario_name] Stopping test containers .." | tee -a $scenario_log
+ docker-compose -p ${project_name} -f ${compose_file} kill 2>&1 | tee -a $scenario_log > /dev/null
+
+fi
+
+</#noparse>
+
+#copy logs
+echo "Copying container logs .." >> $scenario_log
+
+<#list services as service>
+service_name="${service.name}"
+<#noparse>
+docker logs ${project_name}_${service_name}_1 &> $SCENARIO_HOME/logs/${service_name}.log
+</#noparse>
+
+</#list>
+
+<#noparse>
+if [[ "$debug_mode" != "1" && $status == 0 ]];then
+ docker-compose -p $project_name -f $compose_file rm -f 2>&1 | tee -a $scenario_log > /dev/null
+ ${removeImagesScript}
+fi
+
+# clear network
+docker network rm $network_name 2>&1 | tee -a $scenario_log > /dev/null
+
+exit $status
+
+</#noparse>
\ No newline at end of file
diff --git a/test/dubbo-test-runner/build.sh b/test/dubbo-test-runner/build.sh
new file mode 100755
index 0000000..d34a42d
--- /dev/null
+++ b/test/dubbo-test-runner/build.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+DOCKER_DIR=$DIR/target/docker
+
+mvn clean package
+result=$?
+if [ $result -ne 0 ]; then
+ echo "Build dubbo-test-runner failure"
+ exit $result
+fi
+
+mkdir -p $DOCKER_DIR
+cp -r $DIR/src/docker/* $DOCKER_DIR/
+cp $DIR/target/dubbo-test-runner-*-jar-with-dependencies.jar $DOCKER_DIR/
+
+cd $DOCKER_DIR
+docker build -t dubbo/sample-test .
diff --git a/test/dubbo-test-runner/pom.xml b/test/dubbo-test-runner/pom.xml
new file mode 100644
index 0000000..b91e715
--- /dev/null
+++ b/test/dubbo-test-runner/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>dubbo-test</artifactId>
+ <groupId>org.apache.dubbo</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>dubbo-test-runner</artifactId>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-junit4</artifactId>
+ <version>2.22.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>maven-surefire-common</artifactId>
+ <version>2.22.2</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>maven-core</artifactId>
+ <groupId>org.apache.maven</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>maven-plugin-descriptor</artifactId>
+ <groupId>org.apache.maven</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>maven-project</artifactId>
+ <groupId>org.apache.maven</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>asm</artifactId>
+ <groupId>org.ow2.asm</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>3.3.0</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <archive>
+ <manifest>
+ <mainClass>org.apache.dubbo.test.runner.TestRunnerMain</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id> <!-- this is used for inheritance merges -->
+ <phase>package</phase> <!-- bind to the packaging phase -->
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/test/dubbo-test-runner/src/docker/Dockerfile b/test/dubbo-test-runner/src/docker/Dockerfile
new file mode 100644
index 0000000..ad7ef51
--- /dev/null
+++ b/test/dubbo-test-runner/src/docker/Dockerfile
@@ -0,0 +1,61 @@
+# 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.
+
+FROM openjdk:8
+
+RUN apt-get update && \
+ apt-get upgrade -y && \
+ apt-get install -y telnet && \
+ apt-get clean
+
+VOLUME /usr/local/dubbo/app
+VOLUME /usr/local/dubbo/logs
+
+# service name
+ENV SERVICE_NAME=""
+
+# classpath
+# assert mounting $project_dir/target:/usr/local/dubbo/app/
+ENV TEST_CLASSES_DIR="/usr/local/dubbo/app/test-classes"
+ENV APP_CLASSES_DIR="/usr/local/dubbo/app/classes"
+ENV APP_DEPENDENCY_DIR="/usr/local/dubbo/app/dependency"
+
+# check ports/log timeout
+ENV CHECK_TIMEOUT=60
+
+# service type: app, test
+ENV SERVICE_TYPE="app"
+ENV WAIT_PORTS_BEFORE_RUN=""
+
+# dubbo provider bootstrap class
+ENV APP_MAIN_CLASS=""
+ENV CHECK_PORTS_AFTER_RUN=""
+ENV CHECK_LOG=""
+
+# test envs
+ENV TEST_PATTERNS="**/*IT.class"
+
+# Jvm flags
+ENV JAVA_OPTS=""
+
+
+ADD *.sh /usr/local/dubbo/
+ADD dubbo-test-runner-*-jar-with-dependencies.jar /usr/local/dubbo/dubbo-test-runner.jar
+
+WORKDIR /usr/local/dubbo/
+#ENTRYPOINT exec java $JAVA_OPTS -jar dubbo-test-runner.jar $TEST_CLASSES_DIR $APP_CLASSES_DIR $APP_DEPENDENCY_DIR
+ENTRYPOINT ["bash", "-x", "./run.sh"]
+
+
diff --git a/test/dubbo-test-runner/src/docker/run-dubbo-app.sh b/test/dubbo-test-runner/src/docker/run-dubbo-app.sh
new file mode 100755
index 0000000..6fe3d2c
--- /dev/null
+++ b/test/dubbo-test-runner/src/docker/run-dubbo-app.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+DIR=/usr/local/dubbo/
+cd $DIR
+
+source $DIR/utils.sh
+
+if [ "$APP_MAIN_CLASS" == "" ]; then
+ echo "Missing env 'APP_MAIN_CLASS' for app service"
+ return 1
+fi
+
+# wait ports before run app: WAIT_PORTS_BEFORE_RUN=host:port;host:port
+if [ "$WAIT_PORTS_BEFORE_RUN" != "" ]; then
+ echo "Waiting ports before run app .."
+ # check ports
+ split_and_check_tcp_ports "$WAIT_PORTS_BEFORE_RUN" $SECONDS $CHECK_TIMEOUT
+ result=$?
+ if [ $result -ne 0 ]; then
+ echo "Wait ports before run app failure"
+ exit $result
+ fi
+fi
+
+echo "Running app : [$APP_MAIN_CLASS] ..."
+start=$SECONDS
+java $JAVA_OPTS -cp "$APP_CLASSES_DIR:$APP_DEPENDENCY_DIR/*" $APP_MAIN_CLASS 2>&1 &
+pid=$!
+
+sleep 20
+
+# check ports after run
+if [ "$CHECK_PORTS_AFTER_RUN" != "" ]; then
+ split_and_check_tcp_ports "$CHECK_PORTS_AFTER_RUN" $start $CHECK_TIMEOUT
+ result=$?
+ if [ $result -ne 0 ]; then
+ echo "Wait ports after run app failure"
+ exit $result
+ fi
+fi
+
+echo "Wait for process to exit: $pid .."
+wait $pid
+result=$?
+if [ $result -ne 0 ]; then
+ exit $result
+fi
+
diff --git a/test/dubbo-test-runner/src/docker/run-dubbo-test.sh b/test/dubbo-test-runner/src/docker/run-dubbo-test.sh
new file mode 100755
index 0000000..d950974
--- /dev/null
+++ b/test/dubbo-test-runner/src/docker/run-dubbo-test.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+DIR=/usr/local/dubbo/
+
+source $DIR/utils.sh
+
+cd $DIR
+
+if [ "$TEST_CLASSES_DIR" == "" ]; then
+ echo "Missing env 'TEST_CLASSES_DIR' for test service"
+ return 1
+fi
+
+# wait ports before run app: WAIT_PORTS_BEFORE_RUN=host:port;host:port
+if [ "$WAIT_PORTS_BEFORE_RUN" != "" ]; then
+ echo "Waiting ports before run test .."
+ # check ports
+ split_and_check_tcp_ports "$WAIT_PORTS_BEFORE_RUN" $SECONDS $CHECK_TIMEOUT
+ result=$?
+ if [ $result -ne 0 ]; then
+ echo "Wait ports before run test failure"
+ exit $result
+ fi
+fi
+
+# run testcase
+echo "Running tests ..."
+report_dir=$DIR/app/test-reports
+java $JAVA_OPTS -jar dubbo-test-runner.jar "$TEST_CLASSES_DIR" "$APP_CLASSES_DIR" "$APP_DEPENDENCY_DIR" "$report_dir" "$TEST_PATTERNS" 2>&1
+result=$?
+if [ $result -ne 0 ]; then
+ echo "Run tests failure"
+ exit $result
+else
+ echo "Run tests successfully"
+fi
diff --git a/test/dubbo-test-runner/src/docker/run.sh b/test/dubbo-test-runner/src/docker/run.sh
new file mode 100755
index 0000000..e52479e
--- /dev/null
+++ b/test/dubbo-test-runner/src/docker/run.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+DIR=/usr/local/dubbo/
+cd $DIR
+
+LOG_DIR=/usr/local/dubbo/logs
+if [ ! -d $LOG_DIR ];then
+ mkdir -p $LOG_DIR
+fi
+LOG_FILE=$LOG_DIR/$SERVICE_NAME.log
+rm -f $LOG_FILE
+
+source $DIR/utils.sh
+
+function print_log() {
+ msg=$1
+ echo $msg | tee -a $LOG_FILE
+}
+
+if [ "$SERVICE_NAME" == "" ]; then
+ print_log "Missing env 'SERVICE_NAME'"
+ return 1
+fi
+
+if [ "$APP_CLASSES_DIR" == "" ]; then
+ print_log "Missing env 'APP_CLASSES_DIR'"
+ return 1
+fi
+
+if [ "$APP_DEPENDENCY_DIR" == "" ]; then
+ print_log "Missing env 'APP_DEPENDENCY_DIR'"
+ return 1
+fi
+
+
+if [ "$SERVICE_TYPE" == "app" ]; then
+ script_file=$DIR/run-dubbo-app.sh
+elif [ "$SERVICE_TYPE" == "test" ]; then
+ script_file=$DIR/run-dubbo-test.sh
+fi
+
+/bin/bash -x $script_file 2>&1 | tee -a $LOG_FILE
+# get proc exitcode before tee, use $PIPESTATUS variable instead of $? (https://stackoverflow.com/a/6871917)
+result=${PIPESTATUS[0]}
+exit $result
\ No newline at end of file
diff --git a/test/dubbo-test-runner/src/docker/utils.sh b/test/dubbo-test-runner/src/docker/utils.sh
new file mode 100644
index 0000000..76e0650
--- /dev/null
+++ b/test/dubbo-test-runner/src/docker/utils.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+function check_tcp_port() {
+ host=$1
+ port=$2
+ start=$3
+ timeout=$4
+
+ start=${start:-$SECONDS}
+ timeout=${timeout:-60}
+
+ if [[ "$host" == "" || "$port" == "" ]]; then
+ echo "invalid args, usage: check_tcp_port <host> <port> [start_at_seconds] [timeout_in_seconds]"
+ return 1
+ fi
+
+ echo "checking tcp port [$host:$port] ..."
+ for ((i=1; i<=${timeout}; i++));
+ do
+ # sometimes nc/ping is too slowly, why?
+ #nc -zv -w2 $host $port
+
+ # connect to remote host:port by telnet, and auto close it
+ echo -e '\x1dclose\x0d' | telnet $host $port 2>&1
+ result=$?
+ if [ $result -eq 0 ]; then
+ echo "check tcp port [$host:$port] success."
+ return 0
+ fi
+
+ duration=$(( SECONDS - start ))
+ if [ $duration -gt $timeout ];then
+ echo "check tcp port [$host:$port] is timeout: $duration s"
+ return 1
+ fi
+ sleep 1
+ done
+
+ duration=$(( SECONDS - start ))
+ echo "check tcp port [$host:$port] is timeout: $duration s"
+ return 1
+}
+
+function split_and_check_tcp_ports() {
+ addrs_str=$1
+ start=$2
+ timeout=$3
+
+ start=${start:-$SECONDS}
+ timeout=${timeout:-60}
+ echo "checking tcp ports: $addrs_str, start at: $start, timeout: $timeout"
+
+ addr_ports=$(echo $addrs_str | tr ";" "\n")
+ for addr_port in $addr_ports
+ do
+ # process
+ host=${addr_port%:*}
+ port=${addr_port#*:}
+
+ check_tcp_port $host $port $start $timeout
+ result=$?
+ if [ $result -ne 0 ]; then
+ return $result
+ fi
+ done
+}
+
+# examples
+#sleep 3
+#split_and_check_tcp_ports "$@" $SECONDS 10
+
+
+# check and wait for log message
+function check_log() {
+ file="$1"
+ match_str="$2"
+ start=$3
+ timeout=$4
+
+ start=${start:-$SECONDS}
+ timeout=${timeout:-60}
+
+ echo "checking log [$file], matching str: $match_str .."
+ for ((i=1; i<=${timeout}; i++));
+ do
+ grep "$match_str" "$file"
+ result=$?
+ if [ $result -eq 0 ];then
+ return 0
+ fi
+
+ duration=$(( SECONDS - start ))
+ if [ $duration -gt $timeout ];then
+ echo "check log [$file] for matching string [$match_str] is timeout: $duration s"
+ return 1
+ fi
+
+ sleep 2
+ done
+
+ duration=$(( SECONDS - start ))
+ echo "check log [$file] for matching string [$match_str] is timeout: $duration s"
+ return 1
+}
+
+# examples
+#sleep 3
+#check_log "$@" $SECONDS 10
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
new file mode 100644
index 0000000..fd0ba07
--- /dev/null
+++ b/test/dubbo-test-runner/src/main/java/org/apache/dubbo/test/runner/TestRunnerMain.java
@@ -0,0 +1,245 @@
+/*
+ * 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 org.apache.maven.plugin.surefire.InPluginVMSurefireStarter;
+import org.apache.maven.plugin.surefire.StartupReportConfiguration;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.plugin.surefire.log.api.PrintStreamLogger;
+import org.apache.maven.plugin.surefire.report.ConsoleReporter;
+import org.apache.maven.plugin.surefire.util.DirectoryScanner;
+import org.apache.maven.surefire.booter.AbstractPathConfiguration;
+import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
+import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.booter.ClasspathConfiguration;
+import org.apache.maven.surefire.booter.ProviderConfiguration;
+import org.apache.maven.surefire.booter.Shutdown;
+import org.apache.maven.surefire.booter.StartupConfiguration;
+import org.apache.maven.surefire.cli.CommandLineOption;
+import org.apache.maven.surefire.junit4.JUnit4Provider;
+import org.apache.maven.surefire.report.ReporterConfiguration;
+import org.apache.maven.surefire.suite.RunResult;
+import org.apache.maven.surefire.testset.DirectoryScannerParameters;
+import org.apache.maven.surefire.testset.RunOrderParameters;
+import org.apache.maven.surefire.testset.TestListResolver;
+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 {
+
+ if (args.length < 4) {
+ throw new IllegalArgumentException("Invalid arguments, usage: TestRunnerMain <testClassesDir> <targetClassesDir> <dependencyJarsDir> <reportDir> [test-pattern1;test-pattern2]");
+ }
+
+ File testClassesDir = new File(args[0]);
+ if (!testClassesDir.exists() || !testClassesDir.isDirectory()) {
+ throw new IllegalArgumentException("testClassesDir is not exists or is not a directory: " + testClassesDir.getAbsolutePath());
+ }
+ File targetClassesDir = new File(args[1]);
+ if (!targetClassesDir.exists() || !targetClassesDir.isDirectory()) {
+ throw new IllegalArgumentException("targetClassesDir is not exists or is not a directory: " + targetClassesDir.getAbsolutePath());
+ }
+ File dependencyJarsDir = new File(args[2]);
+ if (!dependencyJarsDir.exists() || !dependencyJarsDir.isDirectory()) {
+ throw new IllegalArgumentException("dependencyJarsDir is not exists or is not a directory: " + dependencyJarsDir.getAbsolutePath());
+ }
+
+ File reportsDirectory = new File(args[3]);
+ reportsDirectory.mkdirs();
+ if (!reportsDirectory.exists() || !reportsDirectory.isDirectory()) {
+ throw new IllegalArgumentException("reportDir is not exists or is not a directory: " + reportsDirectory.getAbsolutePath());
+ }
+
+ // tests pattern: **/*IT.class;**/*Test.class
+ List<String> tests = new ArrayList<>();
+ if (args.length > 4) {
+ String[] testPatterns = args[4].split(";");
+ for (String pattern : testPatterns) {
+ String s = pattern.trim();
+ if (s.endsWith(".java")) {
+ s = s.replace(".java", ".class");
+ }
+ tests.add(s);
+ }
+ }
+
+ System.out.println("testClassesDir: " + testClassesDir.getAbsolutePath());
+ System.out.println("targetClassesDir: " + targetClassesDir.getAbsolutePath());
+ System.out.println("dependencyJarsDir: " + dependencyJarsDir.getAbsolutePath());
+ System.out.println("reportsDirectory: " + reportsDirectory.getAbsolutePath());
+ System.out.println("test patterns: " + tests);
+
+
+ File statisticsFile = new File(reportsDirectory, "test-statistics.txt");
+ StartupReportConfiguration startupReportConfiguration = new StartupReportConfiguration(true,
+ true,
+ ConsoleReporter.PLAIN,
+ false,
+ true,
+ reportsDirectory,
+ false,
+ "report",
+ statisticsFile,
+ true,
+ 10,
+ null,
+ "UTF-8",
+ false
+ );
+
+ DirectoryScannerParameters directoryScannerParameters = new DirectoryScannerParameters(testClassesDir,
+ emptyList(), emptyList(), emptyList(), false, "");
+
+ File runStatisticsFile = new File(reportsDirectory, "run-statistics.txt");
+ RunOrderParameters runOrderParameters = new RunOrderParameters((String) null, runStatisticsFile);
+
+ TestListResolver requestTests = new TestListResolver(Collections.emptyList());
+ TestRequest testRequest = new TestRequest(Collections.emptyList(), testClassesDir, requestTests);
+
+ HashMap<String, String> providerProperties = new HashMap<>();
+
+ ReporterConfiguration reporterConfiguration = new ReporterConfiguration(reportsDirectory, false);
+
+ List<CommandLineOption> cliOptions = new ArrayList<>();
+ cliOptions.add(CommandLineOption.LOGGING_LEVEL_ERROR);
+ cliOptions.add(CommandLineOption.LOGGING_LEVEL_WARN);
+ cliOptions.add(CommandLineOption.LOGGING_LEVEL_INFO);
+ cliOptions.add(CommandLineOption.REACTOR_FAIL_FAST);
+
+ ProviderConfiguration providerConfiguration = new ProviderConfiguration(
+ directoryScannerParameters,
+ runOrderParameters,
+ false,
+ reporterConfiguration,
+ null,
+ testRequest,
+ providerProperties,
+ null,
+ false,
+ cliOptions,
+ 0,
+ Shutdown.DEFAULT,
+ 30
+ );
+
+ String providerClassName = JUnit4Provider.class.getName();//"org.apache.maven.surefire.junit4.JUnit4Provider";
+ Classpath testClasspath = generateTestClasspath(testClassesDir, targetClassesDir, dependencyJarsDir);
+ Classpath inprocClasspath = getInprocClasspath();
+ Classpath surefireClasspath = inprocClasspath;
+ AbstractPathConfiguration classpathConfiguration = new ClasspathConfiguration(
+ testClasspath,
+ surefireClasspath,
+ inprocClasspath,
+ false,
+ false
+ );
+
+ ClassLoaderConfiguration classloaderConfiguration = new ClassLoaderConfiguration(false, false);
+ StartupConfiguration startupConfiguration = new StartupConfiguration(
+ providerClassName,
+ classpathConfiguration,
+ classloaderConfiguration,
+ false,
+ false);
+
+
+ DefaultScanResult scanResult = getScanResult(testClassesDir, tests);
+
+ ConsoleLogger consoleLogger = new PrintStreamLogger(System.out);
+ InPluginVMSurefireStarter testStarter = new InPluginVMSurefireStarter(startupConfiguration, providerConfiguration,
+ startupReportConfiguration, consoleLogger);
+ RunResult runResult = testStarter.runSuitesInProcess(scanResult);
+ boolean runSuccess = runResult.getCompletedCount() > 0 && runResult.isErrorFree() && !runResult.isTimeout();
+
+ String line = "------------------------------------------------------------------------\n";
+ consoleLogger.info(String.format(line + "TEST %s, Total: %d, Failures: %d, Errors: %d, Skipped: %d\n" + line,
+ runSuccess ? "SUCCESS" : "FAILURE", runResult.getCompletedCount(), runResult.getFailures(), runResult.getErrors(),
+ runResult.getSkipped()));
+
+// File tmpDirectory = new File(reportsDirectory, "tmp");
+// tmpDirectory.mkdirs();
+// ForkConfiguration forkConfiguration = new ClasspathForkConfiguration(inprocClasspath, tmpDirectory, null,
+// reportsDirectory, new Properties(), "", System.getenv(), false, 1, true,
+// new Platform(), consoleLogger);
+// ForkStarter forkStarter = new ForkStarter(providerConfiguration,
+// startupConfiguration,
+// forkConfiguration,
+// 30,
+// startupReportConfiguration,
+// consoleLogger);
+// RunResult runResult = forkStarter.run(new SurefireProperties(), scanResult);
+// System.out.println(String.format("RunResult: %d, Failures: %d, Errors: %d, failure: %s",
+// runResult.getCompletedCount(), runResult.getFailures(), runResult.getErrors(), runResult.getFailure()));
+
+ if (runSuccess) {
+ System.exit(0);
+ } else {
+ System.exit(1);
+ }
+ }
+
+ public static DefaultScanResult getScanResult(File testClassesDir, Collection<String> tests) {
+ DirectoryScanner directoryScanner = new DirectoryScanner(testClassesDir, new TestListResolver(tests));
+ return directoryScanner.scan();
+ }
+
+ private static Classpath getInprocClasspath() {
+ List<String> classpath = new ArrayList<>();
+
+ ClassLoader cl = ClassLoader.getSystemClassLoader();
+ URL[] urls = ((URLClassLoader) cl).getURLs();
+ for (URL url : urls) {
+ classpath.add(url.getFile());
+ }
+ return new Classpath(classpath);
+ }
+
+ private static Classpath generateTestClasspath(File testClassesDir, File targetClassDir, File dependenciesDir) {
+ List<String> classpath = new ArrayList<>();
+ classpath.add(testClassesDir.getAbsolutePath());
+ classpath.add(targetClassDir.getAbsolutePath());
+
+ File[] jarFiles = dependenciesDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".jar"));
+ if (jarFiles != null) {
+ for (File jarFile : jarFiles) {
+ classpath.add(jarFile.getAbsolutePath());
+ }
+ }
+ return new Classpath(classpath);
+ }
+
+}
\ No newline at end of file
diff --git a/test/kill-tests.sh b/test/kill-tests.sh
new file mode 100755
index 0000000..3736033
--- /dev/null
+++ b/test/kill-tests.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+echo "Killing run-tests.sh .."
+ps -ef | grep run-tests.sh | grep -v grep | awk '{ print $2 }' | xargs -I {} kill {}
+
+echo "Killing scenario.sh .."
+ps -ef | grep scenario.sh | grep -v grep | awk '{ print $2 }' | xargs -I {} kill {}
+
+echo "Killing docker logs procs .."
+ps -ef | grep "docker logs" | grep -v grep | awk '{ print $2 }' | xargs -I {} kill {}
+
+echo "Killing dubbo containers .."
+docker ps -a | grep dubbo | awk '{ print $1}' | xargs -I {} docker kill {}
+
+echo "Removing unused networks .."
+docker network prune -f
+
diff --git a/test/pom.xml b/test/pom.xml
new file mode 100644
index 0000000..b69de03
--- /dev/null
+++ b/test/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <modules>
+ <module>dubbo-scenario-builder</module>
+ <module>dubbo-test-runner</module>
+ </modules>
+ <packaging>pom</packaging>
+
+ <properties>
+ <source.level>1.8</source.level>
+ <target.level>1.8</target.level>
+ <spring.version>4.3.16.RELEASE</spring.version>
+ <junit.version>4.12</junit.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.7.0</version>
+ <configuration>
+ <source>${source.level}</source>
+ <target>${target.level}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/test/prepare-test.sh b/test/prepare-test.sh
new file mode 100755
index 0000000..499d6a2
--- /dev/null
+++ b/test/prepare-test.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+JOB_COUNT=${JOB_COUNT:-5}
+echo "JOB_COUNT: $JOB_COUNT"
+
+# find all case-configuration.yml
+CONFIG_FILE="case-configuration.yml"
+test_list_file=$DIR/testcases.txt
+test_base_dir="$( cd $DIR/.. && pwd )"
+echo "Searching all '$CONFIG_FILE' under dir $test_base_dir .."
+find $test_base_dir -name $CONFIG_FILE | grep -v "$DIR" > $test_list_file
+
+# Split test list into JOB_COUNT parts
+jobs_dir=$DIR/jobs
+mkdir -p $jobs_dir
+rm -f $jobs_dir/*
+case_index=0
+while read file
+do
+ job=$((case_index % JOB_COUNT + 1))
+ case_index=$((case_index + 1))
+ echo ${file%/$CONFIG_FILE} >> $jobs_dir/testcases-${job}.txt
+done < $test_list_file
+
+echo "Total $case_index cases split into $JOB_COUNT jobs:"
+grep -r "" -c $jobs_dir
\ No newline at end of file
diff --git a/test/quick-start_cn.md b/test/quick-start_cn.md
new file mode 100644
index 0000000..96fdf9b
--- /dev/null
+++ b/test/quick-start_cn.md
@@ -0,0 +1,102 @@
+
+
+## Dubbo Integration Test
+
+### 测试框架
+
+* 基于docker-compose 以容器方式运行
+
+* dubbo-test-runner 模块
+
+ 构建`dubbo/sample-test` 镜像,在容器中启动Dubbo provider application 和 Dubbo testcase.
+
+* dubbo-scenario-builder 模块
+
+ 构建测试场景,包含`docker-compose.yml`及`scenario.sh`脚本等。
+ 构建成功后,`scenario.sh`脚本可以单独运行。
+
+### 编译测试镜像
+
+```
+cd dubbo-samples/test
+./build-test-image.sh
+```
+
+### 运行测试案例
+
+#### 编译方式(BUILD)
+
+* `BUILD=all`
+ 编译整个dubbo-samples
+
+* `BUILD=case`
+ 编译需要运行的测试工程(注意有部分测试工程因为依赖问题不能独立编译)
+
+* `BUILD=n`
+ 不自动编译测试工程,需要先手工编译成功后,再运行测试。
+
+ Maven编译参数: mvn clean package dependency:copy-dependencies -DskipTests
+
+#### 测试步骤
+
+* 编译测试工程
+
+ `mvn clean package dependency:copy-dependencies -DskipTests`
+
+* 生成测试场景
+
+ 测试场景`scenario_home`的位置位于`${project.basedir}/target`
+
+ `$scenario_home/scenario.sh`: 运行测试的脚本
+
+ `$scenario_home/docker-compose.yml` : 生成的容器配置文件
+
+ `$scenario_home/logs` : 测试相关日志
+
+* 运行测试
+
+ `$scenario_home/scenario.sh`
+
+#### 运行方式
+
+* 运行全部测试案例
+
+ (1) 编译整个dubbo-samples : `BUILD=all`
+ (2) 查找所有`case-configuration.yml`
+ (3) fork多进程按顺序运行测试
+
+ ```
+ ./run-tests.sh
+ ```
+ 等同于
+ ```
+ BUILD=all ./run-tests.sh
+ ```
+
+* 运行单个测试案例
+
+ `BUILD=case ./run-tests.sh <project.basedir>`
+
+* 调试单个测试案例
+
+ ```
+ BUILD=case DEBUG=1 ./run-tests.sh <project.basedir>
+ ```
+
+ 默认`suspend=y`,可以用`DEBUG_SUSPEND=n`修改为不等待连接调试端口:
+
+ ```
+ BUILD=case DEBUG=1 DEBUG_SUSPEND=n ./run-tests.sh <project.basedir>
+ ```
+
+* 运行指定的测试案例列表
+
+ ```
+ BUILD=case TEST_CASE_FILE=testcases1.txt ./run-tests.sh
+ ```
+
+### 定义测试用例
+
+ 测试用例配置文件为:`case-configuration.yml`,放在每个需要测试的工程basedir下。
+
+
diff --git a/test/run-tests.sh b/test/run-tests.sh
new file mode 100755
index 0000000..065f02f
--- /dev/null
+++ b/test/run-tests.sh
@@ -0,0 +1,290 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+FAIL_FAST=${FAIL_FAST:-0}
+echo "FAIL_FAST: $FAIL_FAST"
+
+SHOW_ERROR_DETAIL=${SHOW_ERROR_DETAIL:-0}
+export SHOW_ERROR_DETAIL=$SHOW_ERROR_DETAIL
+echo "SHOW_ERROR_DETAIL: $SHOW_ERROR_DETAIL"
+
+maxForks=${FORK_COUNT:-2}
+echo "FORK_COUNT: $maxForks"
+
+#Build mode: all, case, no
+BUILD=${BUILD:-all}
+export BUILD=$BUILD
+echo "BUILD: $BUILD"
+
+#DUBBO_VERSION=
+echo "DUBBO_VERSION: $DUBBO_VERSION"
+
+BUILD_OPTS="clean package dependency:copy-dependencies -DskipTests"
+if [ "$DUBBO_VERSION" != "" ]; then
+ BUILD_OPTS="$BUILD_OPTS -Ddubbo.version=$DUBBO_VERSION"
+fi
+export BUILD_OPTS=$BUILD_OPTS
+echo "BUILD_OPTS: $BUILD_OPTS"
+
+#debug
+DEBUG=${DEBUG:-0}
+DEBUG_SUSPEND=${DEBUG_SUSPEND:-y}
+export DEBUG=$DEBUG
+export DEBUG_SUSPEND=$DEBUG_SUSPEND
+echo "DEBUG=$DEBUG, DEBUG_SUSPEND=$DEBUG_SUSPEND"
+
+#TEST_CASE_FILE
+if [ "$TEST_CASE_FILE" != "" ]; then
+ # convert relative path to absolute path
+ if [[ $TEST_CASE_FILE != /* ]]; then
+ TEST_CASE_FILE=$DIR/$TEST_CASE_FILE
+ fi
+ echo "TEST_CASE_FILE: $TEST_CASE_FILE"
+fi
+
+echo "Test logs dir: \${project.basedir}/target/logs"
+echo "Test reports dir: \${project.basedir}/target/test-reports"
+
+
+#check dubbo/sample-test image and version
+test_image="dubbo/sample-test"
+echo "Checking test image [$test_image] .. "
+docker images --format 'table {{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}' | grep $test_image
+result=$?
+if [ $result != 0 ];then
+ echo "Test image not found: $test_image, please run 'bash ./build-test-image.sh' first."
+ exit 1
+fi
+
+# build scenario-builder
+SCENARIO_BUILDER_DIR=$DIR/dubbo-scenario-builder
+echo "Building scenario builder .."
+cd $SCENARIO_BUILDER_DIR
+mvn clean package -DskipTests &> $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"
+ exit $result
+fi
+
+# find jar
+test_builder_jar=`ls $SCENARIO_BUILDER_DIR/target/dubbo-scenario-builder*-with-dependencies.jar`
+if [ "$test_builder_jar" == "" ]; then
+ echo "dubbo-scenario-builder jar not found"
+ exit 1
+else
+ echo "Found test builder : $test_builder_jar"
+fi
+
+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
+
+# prepare testcases
+cd $DIR
+
+CONFIG_FILE="case-configuration.yml"
+
+testListFile=$DIR/testcases.txt
+targetTestcases=$1
+if [ "$targetTestcases" != "" ];then
+ echo "Target testcase: $targetTestcases"
+ echo $targetTestcases > $testListFile
+else
+ # use input testcases file
+ if [ "$TEST_CASE_FILE" != "" ]; then
+ testListFile=$TEST_CASE_FILE
+ if [ ! -f $testListFile ]; then
+ echo "Testcases file not found: $testListFile"
+ exit 1
+ fi
+ else
+ # find all case-configuration.yml
+ test_base_dir="$( cd $DIR/.. && pwd )"
+ rm -f $testListFile
+ echo "Searching all '$CONFIG_FILE' under dir $test_base_dir .."
+ find $test_base_dir -name $CONFIG_FILE | grep -v "$DIR" > $testListFile
+ fi
+fi
+
+caseCount=`grep "" -c $testListFile`
+echo "Total test cases : $caseCount"
+
+#clear test results
+testResultFile=${testListFile%.*}-result.txt
+rm -f $testResultFile
+echo "Test results: $testResultFile"
+
+# constant
+TEST_SUCCESS="TEST SUCCESS"
+TEST_FAILURE="TEST FAILURE"
+
+function print_log_file() {
+ title=$1
+ file=$2
+
+ if [ -f $file ]; then
+ echo ""
+ echo "----------------------------------------------------------"
+ echo " $title"
+ echo "----------------------------------------------------------"
+ cat $file
+ echo ""
+ fi
+}
+
+function process_case() {
+ file=$1
+ case_no=$2
+
+ if [ -d $file ]; then
+ file=$file/$CONFIG_FILE
+ fi
+
+ if [ ! -f $file ]; then
+ echo "$TEST_FAILURE: case config not found: $file" | tee -a $testResultFile
+ return 1
+ fi
+
+ 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 .."
+ cd $project_home
+ mvn $BUILD_OPTS &> $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
+ 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.mode=$DEBUG \
+ -Ddebug.suspend=$DEBUG_SUSPEND \
+ -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
+
+ 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
+ print_log_file "$scenario_name : `basename $log_file`" $log_file
+ done
+ fi
+ return 1
+ fi
+}
+
+# start run tests
+testStartTime=$SECONDS
+
+#counter
+allTest=0
+finishedTest=0
+
+while read line
+do
+ allTest=$((allTest + 1))
+ # fork process testcase
+ process_case $line $allTest &
+ sleep 1
+
+ #wait for tests finished
+ delta=$maxForks
+ if [ $allTest == $caseCount ];then
+ delta=0
+ fi
+ while [ $finishedTest -lt $caseCount ] && [ $((allTest - finishedTest)) -ge $delta ]
+ do
+ sleep 1
+ if [ -f $testResultFile ]; then
+ finishedTest=`grep "" -c $testResultFile`
+ # check fail fast
+ if [ "$FAIL_FAST" == "1" ]; then
+ failedTest=`grep "$TEST_FAILURE" -c $testResultFile`
+ if [ $failedTest -ne 0 ]; then
+ echo "Aborting, wait for subprocess finished .."
+ wait
+ echo "----------------------------------------------------------"
+ echo "Test is aborted cause some testcase is failed (fail-fast mode). "
+ echo "Fail tests:"
+ grep "$TEST_FAILURE" $testResultFile
+ echo "----------------------------------------------------------"
+ exit 1
+ fi
+ fi
+ fi
+ done
+
+done < $testListFile
+
+successTest=`grep "$TEST_SUCCESS" -c $testResultFile`
+failedTest=`grep "$TEST_FAILURE" -c $testResultFile`
+
+echo "----------------------------------------------------------"
+echo "Test logs dir: \${project.basedir}/target/logs"
+echo "Test reports dir: \${project.basedir}/target/test-reports"
+echo "Test results: $testResultFile"
+echo "Total cost: $((SECONDS - testStartTime)) seconds"
+echo "All tests count: $caseCount"
+echo "Success tests count: $successTest"
+
+if [ $successTest == $caseCount ]
+then
+ echo "All tests pass"
+ echo "----------------------------------------------------------"
+ exit 0
+else
+ echo "Some tests fail: $failedTest"
+ echo "----------------------------------------------------------"
+ echo "Fail tests:"
+ grep "$TEST_FAILURE" $testResultFile
+ echo "----------------------------------------------------------"
+ exit 1
+fi
+
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org