Improve test framework (#188)

diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml
index 47394b6..7c04f78 100644
--- a/.github/workflows/java-ci.yml
+++ b/.github/workflows/java-ci.yml
@@ -67,6 +67,9 @@
         uses: actions/setup-java@v1
         with:
           java-version: 1.8
+      - name: Build with Maven
+        run: |
+          ./mvnw  --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
       - name: Download test list result
         uses: actions/download-artifact@v2
         with:
@@ -79,7 +82,7 @@
       - name: Build test image
         run: cd test && bash ./build-test-image.sh
       - name: Run tests
-        run: cd test && bash ./run-tests.sh
+        run: cd test && BUILD=n bash ./run-tests.sh
       - name: Clean images
         run: cd test && bash ./clean-damaged-image.sh
 
@@ -94,13 +97,16 @@
         uses: actions/cache@v2
         with:
           path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
           restore-keys: |
             ${{ runner.os }}-maven-
       - name: Set up JDK 1.8
         uses: actions/setup-java@v1
         with:
           java-version: 1.8
+      - name: Build with Maven
+        run: |
+          ./mvnw  --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
       - name: Download test list result
         uses: actions/download-artifact@v2
         with:
@@ -113,7 +119,7 @@
       - name: Build test image
         run: cd test && bash ./build-test-image.sh
       - name: Run tests
-        run: cd test && bash ./run-tests.sh
+        run: cd test && BUILD=n bash ./run-tests.sh
       - name: Clean images
         run: cd test && bash ./clean-damaged-image.sh
 
@@ -135,6 +141,9 @@
         uses: actions/setup-java@v1
         with:
           java-version: 1.8
+      - name: Build with Maven
+        run: |
+          ./mvnw  --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
       - name: Download test list result
         uses: actions/download-artifact@v2
         with:
@@ -147,7 +156,7 @@
       - name: Build test image
         run: cd test && bash ./build-test-image.sh
       - name: Run tests
-        run: cd test && bash ./run-tests.sh
+        run: cd test && BUILD=n bash ./run-tests.sh
       - name: Clean images
         run: cd test && bash ./clean-damaged-image.sh
 
@@ -162,13 +171,16 @@
         uses: actions/cache@v2
         with:
           path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
           restore-keys: |
             ${{ runner.os }}-maven-
       - name: Set up JDK 1.8
         uses: actions/setup-java@v1
         with:
           java-version: 1.8
+      - name: Build with Maven
+        run: |
+          ./mvnw  --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
       - name: Download test list result
         uses: actions/download-artifact@v2
         with:
@@ -181,7 +193,7 @@
       - name: Build test image
         run: cd test && bash ./build-test-image.sh
       - name: Run tests
-        run: cd test && bash ./run-tests.sh
+        run: cd test && BUILD=n bash ./run-tests.sh
       - name: Clean images
         run: cd test && bash ./clean-damaged-image.sh
 
@@ -196,13 +208,16 @@
         uses: actions/cache@v2
         with:
           path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
           restore-keys: |
             ${{ runner.os }}-maven-
       - name: Set up JDK 1.8
         uses: actions/setup-java@v1
         with:
           java-version: 1.8
+      - name: Build with Maven
+        run: |
+          ./mvnw  --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
       - name: Download test list result
         uses: actions/download-artifact@v2
         with:
@@ -215,7 +230,7 @@
       - name: Build test image
         run: cd test && bash ./build-test-image.sh
       - name: Run tests
-        run: cd test && bash ./run-tests.sh
+        run: cd test && BUILD=n bash ./run-tests.sh
       - name: Clean images
         run: cd test && bash ./clean-damaged-image.sh
 
@@ -230,13 +245,16 @@
         uses: actions/cache@v2
         with:
           path: ~/.m2/repository
-          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/build-test-image.sh') }}
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/test/pom.xml') }}
           restore-keys: |
             ${{ runner.os }}-maven-
       - name: Set up JDK 1.8
         uses: actions/setup-java@v1
         with:
           java-version: 1.8
+      - name: Build with Maven
+        run: |
+          ./mvnw  --settings .mvn/settings.xml clean package dependency:copy-dependencies -DskipTests
       - name: Download test list result
         uses: actions/download-artifact@v2
         with:
@@ -249,6 +267,6 @@
       - 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 && BUILD=n bash ./run-tests.sh
+      - name: Clean images
         run: cd test && bash ./clean-damaged-image.sh
diff --git a/.travis/prepare-artifact.sh b/.travis/prepare-artifact.sh
deleted file mode 100644
index 01576b0..0000000
--- a/.travis/prepare-artifact.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#! /usr/bin/env bash
-env
-
-if [[ -z "${RELEASE_BRANCH}" ]]; then
-  export INTERGARTION_TEST_VERSION=2.7.8-SNAPSHOT
-else
-  git clone https://github.com/apache/dubbo.git
-  cd dubbo
-  git checkout ${RELEASE_BRANCH}
-  ls
-  ./mvnw clean install -DskipTests -Drevision=${RELEASE_BRANCH}
-  export INTERGARTION_TEST_VERSION=${RELEASE_BRANCH}
-  cd ..
-fi
-
-env|grep INTERGARTION_TEST_VERSION
diff --git a/test/README.md b/test/README.md
index a37cd98..1a3cef0 100644
--- a/test/README.md
+++ b/test/README.md
@@ -12,6 +12,15 @@
 cd dubbo-samples/test
 ./build-test-image.sh
 ```
+
+Use debian mirror through env `DEBIAN_MIRROR`, 
+the following example uses aliyun mirror server [http://mirrors.aliyun.com/ubuntu/](http://mirrors.aliyun.com/ubuntu/) :
+
+```
+cd dubbo-samples/test
+DEBIAN_MIRROR=http://mirrors.aliyun.com ./build-test-image.sh
+```
+
 Rebuild the image after modify any file of the `dubbo-test-runner` project.
 
 #### Step 2 - Add case configuration
@@ -36,7 +45,7 @@
 
 ```
 cd dubbo-samples/test
-./run-tests.sh
+./run-tests.sh <project.basedir>
 ```
 
 ### Builtin parent configuration
@@ -55,7 +64,7 @@
 and test case.
 
 
-**Usages:** 
+**Examples:** 
 
 * `dubbo-samples-annotation` configuration:
 
@@ -206,18 +215,12 @@
  
  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`:
+ Change timeout in `case-configuration.yml`:
  
    ```
    timeout: 120
    ```
    
- (2) Change timeout in command line
- 
- ```
-  timeout=120 bash ${scenario_home}/scenario.sh 
- ```
-
 #### Logs
 
 * Container log
diff --git a/test/build-test-image-use-aliyun-mirror.sh b/test/build-test-image-use-aliyun-mirror.sh
new file mode 100755
index 0000000..2ab7ef5
--- /dev/null
+++ b/test/build-test-image-use-aliyun-mirror.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+DEBIAN_MIRROR=http://mirrors.aliyun.com $DIR/dubbo-test-runner/build.sh
\ No newline at end of file
diff --git a/test/build-test-image.sh b/test/build-test-image.sh
index 2020d7d..a5c488e 100755
--- a/test/build-test-image.sh
+++ b/test/build-test-image.sh
@@ -1,7 +1,10 @@
 #!/bin/bash
 
 # Note: modify follow comment when need refresh github actions docker layer caching
-# dubbo/sample-test updated: 2020.12.25
+# dubbo/sample-test updated: 2020.12.27
+
+# Usages:
+# DEBIAN_MIRROR=http://mirrors.aliyun.com ./build-test-image.sh
 
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
diff --git a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
index c0a2e6e..e5620aa 100644
--- a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
+++ b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/ConfigurationImpl.java
@@ -35,9 +35,11 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -54,6 +56,7 @@
     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_DEBUG_OPTS = "DEBUG_OPTS";
     public static final String ENV_SCENARIO_HOME = "SCENARIO_HOME";
 
     private static final Logger logger = LoggerFactory.getLogger(ConfigurationImpl.class);
@@ -63,9 +66,9 @@
     private String scenarioName;
     private final String scenarioLogDir;
     private int scenarioTimeout = 90;
-    private int javaDebugPort=20660;
-    private int debugTimeout=36000;
-    private String debugSuspend="y";
+    private int javaDebugPort = 20660;
+    private int debugTimeout = 36000;
+    private Set<String> debugServices = new HashSet<>();
 
     public ConfigurationImpl() throws IOException, ConfigureFileNotFoundException {
         String configureFile = System.getProperty("configure.file");
@@ -87,7 +90,18 @@
             scenarioName = new File(configBasedir).getName();
         }
 
+        String debugService = System.getProperty("debug.service");
+        String[] strs = debugService.split(",");
+        for (String str : strs) {
+            str = str.trim();
+            if (StringUtils.isNotBlank(str)) {
+                debugServices.add(str);
+            }
+        }
+
         this.configuration = loadCaseConfiguration(configureFile);
+
+        //set scenario timeout
         if (this.configuration.getTimeout() > 0) {
             scenarioTimeout = this.configuration.getTimeout();
         }
@@ -96,11 +110,14 @@
             scenarioTimeout = Integer.parseInt(timeout);
         }
         if (isDebug()) {
-            scenarioTimeout=debugTimeout;
-            debugSuspend=System.getProperty("debug.suspend", debugSuspend);
+            scenarioTimeout = debugTimeout;
         }
     }
 
+    private boolean isDebug() {
+        return debugServices != null && debugServices.size() > 0;
+    }
+
     private CaseConfiguration loadCaseConfiguration(String configureFile) throws IOException {
         // read 'props'
         String configYaml = readFully(configureFile);
@@ -207,20 +224,22 @@
                 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);
+                    if (debugServices.contains(serviceName)) {
+                        //set java remote debug opts
+                        //-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
+                        int debugPort = nextDebugPort();
+                        String debugOpts = String.format("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=%s", debugPort);
+                        appendEnv(service, ENV_DEBUG_OPTS, debugOpts);
 
-                    //mapping debug port
-                    if (service.getPorts() == null) {
-                        service.setPorts(new ArrayList<>());
+                        //mapping debug port
+                        if (service.getPorts() == null) {
+                            service.setPorts(new ArrayList<>());
+                        }
+                        service.getPorts().add(debugPort + ":" + debugPort);
                     }
-                    service.getPorts().add(debugPort + ":" + debugPort);
                 }
                 if (service.getCheckTimeout() > 0) {
-                    setEnv(service, ENV_CHECK_TIMEOUT, service.getCheckTimeout()+"");
+                    setEnv(service, ENV_CHECK_TIMEOUT, service.getCheckTimeout() + "");
                 }
 
                 if ("app".equals(type)) {
@@ -446,11 +465,7 @@
 
     @Override
     public String debugMode() {
-        return System.getProperty("debug.mode", "0");
-    }
-
-    private boolean isDebug() {
-        return "1".equals(debugMode());
+        return isDebug() ? "1" : "0";
     }
 
     private int nextDebugPort() {
diff --git a/test/dubbo-scenario-builder/src/main/resources/scenario.sh b/test/dubbo-scenario-builder/src/main/resources/scenario.sh
index 29ae046..0376a69 100644
--- a/test/dubbo-scenario-builder/src/main/resources/scenario.sh
+++ b/test/dubbo-scenario-builder/src/main/resources/scenario.sh
@@ -23,28 +23,41 @@
 
 # set vars from freemarker
 testcase_name=${scenario_name}-${scenario_version}
-config_debug_mode=${debug_mode}
-config_timeout=${timeout}
+debug_mode=${debug_mode}
+timeout=${timeout}
 scenario_name=${scenario_name}
+scenario_version=${scenario_version}
 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}"
 
+function redirect_container_logs() {
+  #copy logs
+  echo "Redirecting container logs .." >> $scenario_log
+
+  if [ "$debug_mode" == "1" ]; then
+    # redirect container logs to file and display debug message
+    <#list services as service>
+    service_name="${service.name}"
+    <#noparse>
+    docker logs -f ${project_name}_${service_name}_1 2>&1 | tee $SCENARIO_HOME/logs/${service_name}.log | grep "dt_socket" &
+    </#noparse>
+
+    </#list>
+  else
+    # redirect container logs to file
+    <#list services as service>
+    service_name="${service.name}"
+    <#noparse>
+    docker logs -f ${project_name}_${service_name}_1 &> $SCENARIO_HOME/logs/${service_name}.log &
+    </#noparse>
+
+    </#list>
+  fi
+}
+
 <#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
@@ -72,25 +85,39 @@
   done
 }
 
+status=1
+start=$SECONDS
+
+mkdir -p ${SCENARIO_HOME}/logs
+scenario_log=${SCENARIO_HOME}/logs/scenario.log
+rm -f $scenario_log
+
+echo "[$scenario_name] debug_mode: $debug_mode" >> $scenario_log
+echo "[$scenario_name] timeout: $timeout" >> $scenario_log
+
 #Starting test containers
 container_name="${project_name}_${test_service_name}"
 
 #kill and clean first
-echo "[$scenario_name] Killing test containers .." | tee -a $scenario_log
+echo "[$scenario_name] Killing 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
+echo "[$scenario_name] Removing 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
+echo "[$scenario_name] Starting 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
 
+sleep 2
+redirect_container_logs
+
 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
+    echo "[$scenario_name] Waiting for test container .." | tee -a $scenario_log
     # check and get exit code
     wait_container_exit ${container_name} $start $timeout
     result=$?
@@ -108,31 +135,17 @@
         echo "[$scenario_name] Run tests timeout" | tee -a $scenario_log
     fi
 
-    echo "[$scenario_name] Stopping test containers .." | tee -a $scenario_log
+    echo "[$scenario_name] Stopping containers .." | tee -a $scenario_log
     docker-compose -p ${project_name} -f ${compose_file} kill 2>&1 | tee -a $scenario_log > /dev/null
 
 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
+if [[ $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
+# rm network
 docker network rm $network_name 2>&1 | tee -a $scenario_log > /dev/null
 
 exit $status
diff --git a/test/dubbo-test-runner/build.sh b/test/dubbo-test-runner/build.sh
index d34a42d..b1b31fb 100755
--- a/test/dubbo-test-runner/build.sh
+++ b/test/dubbo-test-runner/build.sh
@@ -4,7 +4,9 @@
 
 DOCKER_DIR=$DIR/target/docker
 
-mvn clean package
+echo "Building dubbo-test-runner .."
+cd $DIR
+mvn clean package -DskipTests
 result=$?
 if [ $result -ne 0 ]; then
   echo "Build dubbo-test-runner failure"
@@ -16,4 +18,4 @@
 cp $DIR/target/dubbo-test-runner-*-jar-with-dependencies.jar $DOCKER_DIR/
 
 cd $DOCKER_DIR
-docker build -t dubbo/sample-test .
+docker build -t dubbo/sample-test . --build-arg DEBIAN_MIRROR=$DEBIAN_MIRROR
diff --git a/test/dubbo-test-runner/src/docker/Dockerfile b/test/dubbo-test-runner/src/docker/Dockerfile
index ad7ef51..eb1b4f9 100644
--- a/test/dubbo-test-runner/src/docker/Dockerfile
+++ b/test/dubbo-test-runner/src/docker/Dockerfile
@@ -15,14 +15,23 @@
 
 FROM openjdk:8
 
+ARG DEBIAN_MIRROR
+RUN if [ -n "$DEBIAN_MIRROR" ]; then \
+  sed -i "s@http://deb.debian.org@${DEBIAN_MIRROR}@g" /etc/apt/sources.list && \
+  sed -i "s@http://security.debian.org@${DEBIAN_MIRROR}@g" /etc/apt/sources.list && \
+  cat /etc/apt/sources.list ; fi
+
 RUN apt-get update && \
-    apt-get upgrade -y && \
-    apt-get install -y telnet && \
-    apt-get clean
+  apt-get install -y telnet && \
+  rm -rf /var/lib/apt/lists/*
 
 VOLUME /usr/local/dubbo/app
 VOLUME /usr/local/dubbo/logs
 
+# Jvm flags
+ENV JAVA_OPTS=""
+ENV DEBUG_OPTS=""
+
 # service name
 ENV SERVICE_NAME=""
 
@@ -47,9 +56,6 @@
 # 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
diff --git a/test/dubbo-test-runner/src/docker/run-dubbo-app.sh b/test/dubbo-test-runner/src/docker/run-dubbo-app.sh
index 6fe3d2c..ae4d089 100755
--- a/test/dubbo-test-runner/src/docker/run-dubbo-app.sh
+++ b/test/dubbo-test-runner/src/docker/run-dubbo-app.sh
@@ -24,7 +24,7 @@
 
 echo "Running app : [$APP_MAIN_CLASS] ..."
 start=$SECONDS
-java $JAVA_OPTS -cp "$APP_CLASSES_DIR:$APP_DEPENDENCY_DIR/*" $APP_MAIN_CLASS 2>&1 &
+java $JAVA_OPTS $DEBUG_OPTS -cp "$APP_CLASSES_DIR:$APP_DEPENDENCY_DIR/*" $APP_MAIN_CLASS 2>&1 &
 pid=$!
 
 sleep 20
diff --git a/test/dubbo-test-runner/src/docker/run-dubbo-test.sh b/test/dubbo-test-runner/src/docker/run-dubbo-test.sh
index d950974..47a1de9 100755
--- a/test/dubbo-test-runner/src/docker/run-dubbo-test.sh
+++ b/test/dubbo-test-runner/src/docker/run-dubbo-test.sh
@@ -26,7 +26,7 @@
 # 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
+java $JAVA_OPTS $DEBUG_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"
diff --git a/test/dubbo-test-runner/src/docker/run.sh b/test/dubbo-test-runner/src/docker/run.sh
index e52479e..08fcaf5 100755
--- a/test/dubbo-test-runner/src/docker/run.sh
+++ b/test/dubbo-test-runner/src/docker/run.sh
@@ -3,18 +3,19 @@
 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
+#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
+    echo $msg
+#    echo $msg | tee -a $LOG_FILE
 }
 
 if [ "$SERVICE_NAME" == "" ]; then
@@ -39,7 +40,9 @@
   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
+/bin/bash -x $script_file 2>&1
+
+#/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/quick-start_cn.md b/test/quick-start_cn.md
index 96fdf9b..16dfa9a 100644
--- a/test/quick-start_cn.md
+++ b/test/quick-start_cn.md
@@ -22,25 +22,166 @@
 ./build-test-image.sh
 ```
 
+如果构建镜像时apt更新数据很缓慢,可以使用Debian镜像服务器加快构建速度。
+通过设置环境变量`DEBIAN_MIRROR=http_mirror_server`来指定Debian镜像地址,
+比如下面脚本指定使用aliyun镜像服务器[http://mirrors.aliyun.com/ubuntu/](http://mirrors.aliyun.com/ubuntu/) :
+
+```
+cd dubbo-samples/test
+DEBIAN_MIRROR=http://mirrors.aliyun.com ./build-test-image.sh
+```
+
+也可以执行封装好的脚本:
+
+```
+cd dubbo-samples/test
+./build-test-image-use-aliyun-mirror.sh
+```
+
 ### 运行测试案例
 
+通过`run-tests.sh`运行单个测试案例、测试案例列表或者全部测试案例。
+
 #### 编译方式(BUILD)
 
+默认值为`BUILD=case`,即每个case工程单独编译。
+
+* `BUILD=case`  
+
+  单独编译需要运行的测试工程。
+  
+  注意:有部分测试工程因为依赖问题不能独立编译,此时需要改为整体编译或者手工编译。
+
 * `BUILD=all`  
+
   编译整个dubbo-samples
   
-* `BUILD=case`  
-  编译需要运行的测试工程(注意有部分测试工程因为依赖问题不能独立编译)
-
 * `BUILD=n`  
+
   不自动编译测试工程,需要先手工编译成功后,再运行测试。
   
   Maven编译参数: mvn clean package dependency:copy-dependencies -DskipTests
 
-#### 测试步骤
 
+#### 运行方式
+
+* 运行单个测试案例
+
+  `./run-tests.sh <project.basedir>`
+  
+* 调试单个测试案例
+
+  ```
+  DEBUG=service1,service2 ./run-tests.sh <project.basedir>
+  ```
+
+  可以通过设置环境变量`DEBUG=service1,service2`来指定哪些app/test服务开启远程调试,自动分配debug端口,
+  具体端口可以查看生成的`docker-compose.yml`文件。
+  
+  注意:调试运行为`suspend=y`模式,Java应用被挂起,等待调试客户端连接才能继续执行Java代码。
+
+  也可以查看日志文件`${scenario_home}/logs/{$service_name}.log`,如出现下面的信息可以知道已经打开调试端口:
+  > Listening for transport dt_socket at address: 20660
+
+* 运行指定的测试案例列表
+
+  ```
+  TEST_CASE_FILE=testcases1.txt ./run-tests.sh
+  ```
+ 
+* 运行全部测试案例
+ 
+  ```
+   BUILD=all  ./run-tests.sh
+  ```
+ 
+  run-tests.sh 运行全部测试案例的原理:
+
+  (1) 编译整个dubbo-samples : `BUILD=all`   
+  (2) 查找所有`case-configuration.yml`  
+  (3) fork多进程按顺序运行测试案例
+   
+   
+#### 调试运行测试案例
+    
+  下面以`dubbo-samples-annotation`举例说明如何调试运行测试案例。
+    
+  先用普通方式执行一次测试案例,查看生成的`docker-compose.yml`,可知AnnotationProviderBootstrap的服务名称为`dubbo-samples-annotation`,
+  test类的服务名为`dubbo-samples-annotation-test`。
+  
+  * 调试provider类:AnnotationProviderBootstrap
+  
+    执行启动命令,以suspend模式启动AnnotationProviderBootstrap:
+    ```
+    DEBUG=dubbo-sampes-annotation ./run-tests.sh ../dubbo-samples-annotation
+    ```
+    
+    用命令查看日志:
+     
+    ```
+    tail -f dubbo-sampes-annotation/target/logs/dubbo-sampes-annotation.log
+    ```
+    
+    直到可以看到下面的日志信息:
+  
+    ```
+    + java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=20660 -cp '/usr/local/dubbo/app/classes:/usr/local/dubbo/app/dependency/*' org.apache.dubbo.samples.annotation.AnnotationProviderBootstrap
+    Listening for transport dt_socket at address: 20660
+    ```
+   
+    要先在IDEA/eclipse上对要调试的代码加上断点,然后才能开始远程调试,这样可以调试应用启动过程。
+
+    比如`AnnotationProviderBootstrap.main()` 第一行进行断点,然后创建远程调试,设置端口为20660。
+    
+    连接上后,开始执行`AnnotationProviderBootstrap`,然后在断点处暂停。
+    
+  * 调试test类:AnnotationServicesIT
+    
+    执行启动命令,以suspend模式启动test:
+    ```
+    DEBUG=dubbo-sampes-annotation-test ./run-tests.sh ../dubbo-samples-annotation
+    ```
+        
+    用命令查看日志:
+     
+    ```
+    tail -f dubbo-sampes-annotation/target/logs/dubbo-sampes-annotation-test.log
+    ```
+    
+    直到可以看到下面的日志信息:
+  
+    ```
+    + java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=20661 -Dzookeeper.address=dubbo-samples-annotation -Dzookeeper.port=2181 -Ddubbo.address=dubbo-samples-annotation -Ddubbo.port=20880 -jar dubbo-test-runner.jar /usr/local/dubbo/app/test-classes /usr/local/dubbo/app/classes /usr/local/dubbo/app/dependency /usr/local/dubbo//app/test-reports '**/*IT.class'
+    Listening for transport dt_socket at address: 20661
+    ```
+    用上面的方法,先断点,然后再连接调试端口20661。
+   
+  * 同时调试provider和test类
+  
+    执行调试启动命令
+    ```
+    DEBUG=dubbo-sampes-annotation,dubbo-sampes-annotation-test ./run-tests.sh ../dubbo-samples-annotation
+    ```
+    
+    如果同时调试多个suspend方式启动的app/test服务,需要按照依赖顺序连接调试端口,保证前置服务启动成功后,才能继续调试后一个服务。
+
+**注意:**
+  
+  test容器启动后先等待dubbo服务端口,循环检查直到连接成功后才启动test类。如果test服务依赖的端口没有连接成功,则test类不会启动,也就不能进行远程调试。
+  
+  所以要保证AnnotationProviderBootstrap启动成功打开20880端口,test容器脚本检查[dubbo-samples-annotation:20880]端口连接成功,
+  然后才会启动dubbo-test-runner执行testcase。
+ 
+   
+#### 测试步骤原理
+
+下面是脚本自动完成的步骤,只需要理解,不需要手工执行。    
+对每个测试案例来说,都会按照下面的步骤进行处理。
+  
 * 编译测试工程
-
+  
+  如果按照case单独编译,则执行下面的编译命令:
+  
   `mvn clean package dependency:copy-dependencies -DskipTests`
   
 * 生成测试场景
@@ -55,45 +196,10 @@
    
 * 运行测试
 
+  启动容器,等待并检查测试结果是否成功。
+  
   `$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
-  ```
     
 ### 定义测试用例
 
diff --git a/test/run-tests.sh b/test/run-tests.sh
index 065f02f..46f7756 100755
--- a/test/run-tests.sh
+++ b/test/run-tests.sh
@@ -2,6 +2,8 @@
 
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
+abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
+
 FAIL_FAST=${FAIL_FAST:-0}
 echo "FAIL_FAST: $FAIL_FAST"
 
@@ -13,32 +15,22 @@
 echo "FORK_COUNT: $maxForks"
 
 #Build mode: all, case, no
-BUILD=${BUILD:-all}
+BUILD=${BUILD:-case}
 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}
+#debug DEBUG=service1,service2
 export DEBUG=$DEBUG
-export DEBUG_SUSPEND=$DEBUG_SUSPEND
-echo "DEBUG=$DEBUG, DEBUG_SUSPEND=$DEBUG_SUSPEND"
+echo "DEBUG=$DEBUG"
 
 #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
+    TEST_CASE_FILE=`abspath $TEST_CASE_FILE`
   fi
   echo "TEST_CASE_FILE: $TEST_CASE_FILE"
 fi
@@ -57,36 +49,6 @@
   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
@@ -96,8 +58,14 @@
 testListFile=$DIR/testcases.txt
 targetTestcases=$1
 if [ "$targetTestcases" != "" ];then
-  echo "Target testcase: $targetTestcases"
-  echo $targetTestcases > $testListFile
+  targetTestcases=`abspath $targetTestcases`
+  if [ -d "$targetTestcases" ] || [ -f "$targetTestcases" ]; then
+    echo "Target testcase: $targetTestcases"
+    echo $targetTestcases > $testListFile
+  else
+    echo "Testcase not exist: $targetTestcases"
+    exit 1
+  fi
 else
   # use input testcases file
   if [ "$TEST_CASE_FILE" != "" ]; then
@@ -118,11 +86,23 @@
 caseCount=`grep "" -c $testListFile`
 echo "Total test cases : $caseCount"
 
+if [ "$DEBUG" != "" ] && [ $caseCount -gt 1 ]; then
+  echo "Only one case can be debugged"
+  exit 1
+fi
+
 #clear test results
 testResultFile=${testListFile%.*}-result.txt
 rm -f $testResultFile
 echo "Test results: $testResultFile"
 
+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"
+
 # constant
 TEST_SUCCESS="TEST SUCCESS"
 TEST_FAILURE="TEST FAILURE"
@@ -189,8 +169,7 @@
     -Dscenario.home=$scenario_home \
     -Dscenario.name=$scenario_name \
     -Dscenario.version=$DUBBO_VERSION \
-    -Ddebug.mode=$DEBUG \
-    -Ddebug.suspend=$DEBUG_SUSPEND \
+    -Ddebug.service=$DEBUG \
     -jar $test_builder_jar  &> $scenario_home/logs/scenario-builder.log
   result=$?
   if [ $result -ne 0 ]; then
@@ -213,14 +192,51 @@
     # 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
+        # ignore scenario-builder.log
+        if [[ $log_file != *scenario-builder.log ]]; then
+          print_log_file "$scenario_name : `basename $log_file`" $log_file
+        fi
       done
     fi
     return 1
   fi
 }
 
+# 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
+
+# build all samples
+if [ "$BUILD" == "all" ]; then
+  echo "Building dubbo-samples .."
+  cd $DIR/..
+  mvn $BUILD_OPTS
+  result=$?
+  if [ $result -ne 0 ]; then
+    echo "Build dubbo-samples failure, please check logs"
+    exit $result
+  fi
+fi
+
+
 # start run tests
+cd $DIR
 testStartTime=$SECONDS
 
 #counter