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

albumenj 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 d37f196  Support version range matching, improve test scripts (#275)
d37f196 is described below

commit d37f1966f05111370110c9f848495c177da0b332
Author: Gong Dewei <[email protected]>
AuthorDate: Tue Mar 16 16:11:47 2021 +0800

    Support version range matching, improve test scripts (#275)
---
 README.md                                          |  18 +-
 dubbo-samples-zipkin/case-versions.conf            |   4 +-
 test/README.md                                     |  18 +-
 .../dubbo/scenario/builder/VersionMatcher.java     | 399 ++++++++++++++++++---
 .../dubbo/scenario/builder/VersionMatcherTest.java | 220 +++++++++++-
 test/quick-start_cn.md                             | 137 +++++--
 test/run-tests.sh                                  | 220 ++++++------
 7 files changed, 798 insertions(+), 218 deletions(-)

diff --git a/README.md b/README.md
index f0c1768..66a88f3 100644
--- a/README.md
+++ b/README.md
@@ -32,16 +32,16 @@ Integration test leverages 
[docker](https://docs.docker.com/get-started/) to set
 Please install `docker` and `docker-compose` first, then build the test image 
`dubb/sample-test`.
 
 ```bash
-cd dubbo-samples/test
-./build-test-image.sh
+cd dubbo-samples
+./test/build-test-image.sh
 ```
 
 Use a debian mirror through env `DEBIAN_MIRROR` if apt download files slowly, 
 the following example uses aliyun mirror server 
[http://mirrors.aliyun.com/ubuntu/](http://mirrors.aliyun.com/ubuntu/) :
 
 ```bash
-cd dubbo-samples/test
-DEBIAN_MIRROR=http://mirrors.aliyun.com ./build-test-image.sh
+cd dubbo-samples
+DEBIAN_MIRROR=http://mirrors.aliyun.com ./test/build-test-image.sh
 ```
 
 Then we use the `run-tests.sh` script to run the test cases.
@@ -49,21 +49,21 @@ Then we use the `run-tests.sh` script to run the test cases.
 * Run single test case
 
   ```bash
-  cd dubbo-samples/test
-  ./run-tests.sh <project.basedir>
+  cd dubbo-samples
+  ./test/run-tests.sh <project.basedir>
   ```
     
   For example, run the `dubbo-samples-annotation` test case:
     
   ```
-  ./run-tests.sh ../dubbo-samples-annotation
+  ./test/run-tests.sh dubbo-samples-annotation
   ```
   
 * Run all test cases
 
   ```bash
-  cd dubbo-samples/test
-  ./run-tests.sh 
+  cd dubbo-samples
+  ./test/run-tests.sh 
   ```
 
 If docker container fails to startup successfully in any case, you can check 
log files in directory `${project.basedir}/target/logs` to understand what 
happens.
diff --git a/dubbo-samples-zipkin/case-versions.conf 
b/dubbo-samples-zipkin/case-versions.conf
index 581882b..aacb840 100644
--- a/dubbo-samples-zipkin/case-versions.conf
+++ b/dubbo-samples-zipkin/case-versions.conf
@@ -20,5 +20,5 @@
 # Supported component versions of the test case
 
 # Spring app
-dubbo.version=2.7*
-spring.version=4.*, 5.*
+dubbo.version=[ <2.7.8, >=2.7.9, >=3.0 ]
+spring.version=[ 4.*, 5.* ]
diff --git a/test/README.md b/test/README.md
index 98c8370..16ace77 100644
--- a/test/README.md
+++ b/test/README.md
@@ -1,4 +1,4 @@
-## Dubbo Integration Test
+## Dubbo Integration Test 
 
 ### Test steps
 
@@ -9,16 +9,16 @@ Follow the 3 steps below:
 Please install `docker` and `docker-compose` first, then build the test image.
 
 ```
-cd dubbo-samples/test
-./build-test-image.sh
+cd dubbo-samples
+./test/build-test-image.sh
 ```
 
 Use a debian mirror through env `DEBIAN_MIRROR` if apt download files slowly, 
 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
+cd dubbo-samples
+DEBIAN_MIRROR=http://mirrors.aliyun.com ./test/build-test-image.sh
 ```
 
 Rebuild the image after modify any file of the `dubbo-test-runner` project.
@@ -47,15 +47,15 @@ Some example projects:
 Run single test project:
 
 ```
-cd dubbo-samples/test
-./run-tests.sh <project.basedir>
+cd dubbo-samples
+./test/run-tests.sh <project.basedir>
 ```
 
 Run all tests:
 
 ```
-cd dubbo-samples/test
-./run-tests.sh
+cd dubbo-samples
+./test/run-tests.sh
 ```
 
 ### Builtin parent configuration
diff --git 
a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java
 
b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java
index a555d4e..522bb68 100644
--- 
a/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java
+++ 
b/test/dubbo-scenario-builder/src/main/java/org/apache/dubbo/scenario/builder/VersionMatcher.java
@@ -28,9 +28,11 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringReader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
@@ -68,46 +70,61 @@ public class VersionMatcher {
         }
         new File(outputFile).getParentFile().mkdirs();
 
+        VersionMatcher versionMatcher = new VersionMatcher();
+        versionMatcher.doMatch(caseVersionsFile, candidateVersionListStr, 
outputFile, includeCaseSpecificVersion);
+    }
+
+    private void doMatch(String caseVersionsFile, String 
candidateVersionListStr, String outputFile, boolean includeCaseSpecificVersion) 
throws Exception {
         logger.info("{}: {}", CANDIDATE_VERSIONS, candidateVersionListStr);
         logger.info("{}: {}", CASE_VERSIONS_FILE, caseVersionsFile);
         logger.info("{}: {}", OUTPUT_FILE, outputFile);
 
         // parse and expand to versions list
-        List<String> candidateVersionList = 
parseVersionList(candidateVersionListStr);
-
-        // parse case version rules
-        Map<String, List<String>> caseVersionRules = 
parseCaseVersionRules(caseVersionsFile);
-
-        Map<String, List<String>> matchVersions = new LinkedHashMap<>();
-        caseVersionRules.forEach((component, versionPatterns) -> {
-            for (String versionPattern : versionPatterns) {
-                // convert 'component:version_prefix*' to regex
-                String regex = "\\Q" + component + ":" + 
versionPattern.replace("*", "\\E.*?\\Q") + "\\E";
-                Pattern pattern = Pattern.compile(regex);
-                boolean matched = false;
-                for (String version : candidateVersionList) {
-                    if (pattern.matcher(version).matches()) {
-                        getMatchVersionList(matchVersions, 
component).add(version);
-                        matched = true;
-                    }
+        Map<String, List<String>> candidateVersionMap = 
parseVersionList(candidateVersionListStr);
+
+        // parse case version match rules
+        Map<String, List<MatchRule>> caseVersionMatchRules = 
parseCaseVersionMatchRules(caseVersionsFile);
+
+        Map<String, List<String>> matchedVersionMap = new LinkedHashMap<>();
+
+        candidateVersionMap.forEach((component, candidateVersionList) -> {
+            List<MatchRule> matchRules = caseVersionMatchRules.get(component);
+            if (matchRules == null || matchRules.isEmpty()) {
+                return;
+            }
+
+            // matching rules
+            List<String> matchedVersionList = new ArrayList<>();
+            for (String version : candidateVersionList) {
+                if (hasIncludeVersion(matchRules, version)) {
+                    matchedVersionList.add(version);
                 }
-                //add case specific version
-                if (!matched && includeCaseSpecificVersion && 
!versionPattern.contains("*")) {
-                    getMatchVersionList(matchVersions, 
component).add(component+":"+versionPattern);
+            }
+
+            //add case specific version
+            if (matchedVersionList.isEmpty() && includeCaseSpecificVersion) {
+                for (MatchRule matchRule : matchRules) {
+                    if (!matchRule.isExcluded() && matchRule instanceof 
PlainMatchRule) {
+                        matchedVersionList.add(((PlainMatchRule) 
matchRule).getVersion());
+                    }
                 }
             }
+            if (matchedVersionList.size() > 0) {
+                matchedVersionMap.put(component, matchedVersionList);
+            }
         });
 
-        if (caseVersionRules.size() != matchVersions.size()) {
-            List<String> components = new 
ArrayList<>(caseVersionRules.keySet());
-            components.removeAll(matchVersions.keySet());
+        // check if all component has matched version
+        if (caseVersionMatchRules.size() != matchedVersionMap.size()) {
+            List<String> components = new 
ArrayList<>(caseVersionMatchRules.keySet());
+            components.removeAll(matchedVersionMap.keySet());
             for (String component : components) {
-                errorAndExit(Constants.EXIT_UNMATCHED, "Component not match: 
{}, rules: {}", component, caseVersionRules.get(component));
+                errorAndExit(Constants.EXIT_UNMATCHED, "Component not match: 
{}, rules: {}", component, caseVersionMatchRules.get(component));
             }
         }
 
         List<List<String>> versionProfiles = new ArrayList<>();
-        for (Map.Entry<String, List<String>> entry : matchVersions.entrySet()) 
{
+        for (Map.Entry<String, List<String>> entry : 
matchedVersionMap.entrySet()) {
             String component = entry.getKey();
             List<String> versions = entry.getValue();
             versionProfiles = appendComponent(versionProfiles, component, 
versions);
@@ -124,7 +141,7 @@ public class VersionMatcher {
                 List<String> profile = versionProfiles.get(i);
                 for (String version : profile) {
                     //-Dxxx.version=1.0.0
-                    sb.append("-D").append(version.replace(':','=')).append(" 
");
+                    sb.append("-D").append(version.replace(':', '=')).append(" 
");
                 }
                 sb.append("\n");
             }
@@ -133,26 +150,44 @@ public class VersionMatcher {
         } catch (IOException e) {
             errorAndExit(Constants.EXIT_FAILED, "Write version matrix failed: 
" + e.toString(), e);
         }
+    }
 
+    private static boolean hasIncludeVersion(List<MatchRule> matchRules, 
String version) {
+        boolean included = false;
+        version = trimVersion(version);
+        for (MatchRule matchRule : matchRules) {
+            if (matchRule.match(version)) {
+                // excluded rule has higher priority than included rule
+                if (matchRule.isExcluded()) {
+                    return false;
+                } else {
+                    included = true;
+                }
+            }
+        }
+        return included;
     }
 
-    private static List<String> getMatchVersionList(Map<String, List<String>> 
matchVersions, String component) {
-        return matchVersions.computeIfAbsent(component, (key) -> new 
ArrayList<>());
+    private static Pattern getWildcardPattern(String versionPattern) {
+        // convert 'version_prefix*' to regex
+        String regex = "\\Q" + versionPattern.replace("*", "\\E.*?\\Q") + 
"\\E";
+        return Pattern.compile(regex);
     }
 
     private static List<List<String>> appendComponent(List<List<String>> 
versionProfiles, String component, List<String> versions) {
         List<List<String>> newProfiles = new ArrayList<>();
         for (String version : versions) {
+            String versionProfile = createVersionProfile(component, version);
             if (versionProfiles.isEmpty()) {
                 List<String> newProfile = new ArrayList<>();
-                newProfile.add(version);
+                newProfile.add(versionProfile);
                 newProfiles.add(newProfile);
             } else {
                 //extends version matrix
                 for (int i = 0; i < versionProfiles.size(); i++) {
                     List<String> profile = versionProfiles.get(i);
                     List<String> newProfile = new ArrayList<>(profile);
-                    newProfile.add(version);
+                    newProfile.add(versionProfile);
                     newProfiles.add(newProfile);
                 }
             }
@@ -160,11 +195,20 @@ public class VersionMatcher {
         return newProfiles;
     }
 
-    private static Map<String, List<String>> parseCaseVersionRules(String 
caseVersionsFile) throws Exception {
-        //dubbo.version=2.7*, 3.*
-        //spring.version=4.*, 5.*
+    private static String createVersionProfile(String component, String 
version) {
+        return component + ":" + version;
+    }
+
+    private Map<String, List<MatchRule>> parseCaseVersionMatchRules(String 
caseVersionsFile) throws Exception {
+        // Possible formats:
+        //dubbo.version=2.7*, 3.*, !2.7.8*, !2.7.8.1
+        //dubbo.version=<=2.7.7, >2.7.8, >=3.0
+        //dubbo.version=[<=2.7.7, >2.7.8, >=3.0]
+        //dubbo.version=["<=2.7.7", ">2.7.8", ">=3.0"]
+        //dubbo.version=['<=2.7.7', '>2.7.8', '>=3.0']
+
         try {
-            Map<String, List<String>> ruleMap = new LinkedHashMap<>();
+            Map<String, List<MatchRule>> ruleMap = new LinkedHashMap<>();
             String content = FileUtil.readFully(caseVersionsFile);
             BufferedReader br = new BufferedReader(new StringReader(content));
             String line;
@@ -173,15 +217,31 @@ public class VersionMatcher {
                 if (line.startsWith("#") || StringUtils.isBlank(line)) {
                     continue;
                 }
-                String[] strs = line.split("=");
-                String component = strs[0].trim();
-                String patternStr = strs[1];
+                int p = line.indexOf('=');
+                String component = line.substring(0, p);
+                String patternStr = line.substring(p + 1);
+                patternStr = trimRule(patternStr, "[", "]");
                 String[] patterns = patternStr.split(",");
-                List<String> patternList = new ArrayList<>();
+                List<MatchRule> ruleList = new ArrayList<>();
                 for (String pattern : patterns) {
-                    patternList.add(pattern.trim());
+                    pattern = trimRule(pattern, "\"");
+                    pattern = trimRule(pattern, "'");
+                    if (pattern.startsWith(">") || pattern.startsWith("<")) {
+                        ruleList.add(parseRangeMatchRule(pattern));
+                    } else {
+                        boolean excluded = false;
+                        if (pattern.startsWith("!")) {
+                            excluded = true;
+                            pattern = pattern.substring(1).trim();
+                        }
+                        if (pattern.contains("*")) {
+                            ruleList.add(new WildcardMatchRule(excluded, 
pattern));
+                        } else {
+                            ruleList.add(new PlainMatchRule(excluded, 
pattern));
+                        }
+                    }
                 }
-                ruleMap.put(component, patternList);
+                ruleMap.put(component, ruleList);
             }
             return ruleMap;
         } catch (Exception e) {
@@ -190,11 +250,27 @@ public class VersionMatcher {
         }
     }
 
-    private static List<String> parseVersionList(String versionListStr) {
+    private String trimRule(String rule, String ch) {
+        return trimRule(rule, ch, ch);
+    }
+
+    private String trimRule(String rule, String begin, String end) {
+        rule = rule.trim();
+        if (rule.startsWith(begin)) {
+            if (rule.endsWith(end)){
+                return rule.substring(1, rule.length()-1);
+            } else {
+                throw new IllegalArgumentException("Version match rule is 
invalid: "+rule);
+            }
+        }
+        return rule;
+    }
+
+    private Map<String, List<String>> parseVersionList(String versionListStr) {
         // 
"<component1>:<version1>[,version2];<component2>:<version1>[,version2]"
         // 
"<component1>:<version1>[;component1:<version2];<component2>:<version1>[;component2:version2];"
 
-        List<String> versionList = new ArrayList<>();
+        Map<String, List<String>> versionMap = new LinkedHashMap<>();
         //split components by ';' or '\n'
         String[] compvers = versionListStr.split("[;\n]");
         for (String compver : compvers) {
@@ -204,11 +280,12 @@ public class VersionMatcher {
             String[] strs = compver.split(":");
             String component = strs[0].trim();
             String[] vers = strs[1].split(",");
+            List<String> versionList = versionMap.computeIfAbsent(component, 
(key) -> new ArrayList<>());
             for (String ver : vers) {
-                versionList.add(component + ":" + ver.trim());
+                versionList.add(ver.trim());
             }
         }
-        return versionList;
+        return versionMap;
     }
 
     private static void errorAndExit(int exitCode, String format, Object... 
arguments) {
@@ -219,4 +296,238 @@ public class VersionMatcher {
         logger.error("{} " + format, newArgs);
         System.exit(exitCode);
     }
+
+    private interface MatchRule {
+
+        boolean isExcluded();
+
+        boolean match(String version);
+
+    }
+
+    private static abstract class ExcludableMatchRule implements MatchRule {
+        boolean excluded;
+
+        public ExcludableMatchRule(boolean excluded) {
+            this.excluded = excluded;
+        }
+
+        public boolean isExcluded() {
+            return excluded;
+        }
+
+    }
+
+    private static class PlainMatchRule extends ExcludableMatchRule {
+        private String version;
+
+        public PlainMatchRule(boolean excluded, String version) {
+            super(excluded);
+            this.version = version;
+        }
+
+        @Override
+        public boolean match(String version) {
+            return this.version.equals(version);
+        }
+
+        public String getVersion() {
+            return version;
+        }
+
+        @Override
+        public String toString() {
+            return (excluded?"!":"")+version;
+        }
+    }
+
+    private static class WildcardMatchRule extends ExcludableMatchRule {
+        private Pattern versionPattern;
+        private String versionWildcard;
+
+        public WildcardMatchRule(boolean excluded, String versionWildcard) {
+            super(excluded);
+            this.versionPattern = getWildcardPattern(versionWildcard);
+            this.versionWildcard = versionWildcard;
+        }
+
+        @Override
+        public boolean match(String version) {
+            return this.versionPattern.matcher(version).matches();
+        }
+        @Override
+        public String toString() {
+            return (excluded?"!":"")+versionWildcard;
+        }
+    }
+
+    private static class RangeMatchRule implements MatchRule {
+        private VersionComparator comparator;
+        private String operator;
+        private String version;
+        private int[] versionInts;
+
+        public RangeMatchRule(String operator, String version) {
+            this.operator = operator;
+            this.version = version;
+            this.comparator = getVersionComparator(operator);
+            this.versionInts = toVersionInts(version);
+        }
+
+        @Override
+        public boolean isExcluded() {
+            return false;
+        }
+
+        @Override
+        public boolean match(String matchingVersion) {
+            int[] matchingVersionInts = toVersionInts(matchingVersion);
+            return comparator.match(matchingVersionInts, versionInts);
+        }
+
+        @Override
+        public String toString() {
+            return operator+version;
+        }
+    }
+
+    private static class CombineMatchRule implements MatchRule {
+        List<MatchRule> matchRules = new ArrayList<>();
+
+        public CombineMatchRule(List<MatchRule> matchRules) {
+            this.matchRules.addAll(matchRules);
+        }
+
+        @Override
+        public boolean isExcluded() {
+            return false;
+        }
+
+        @Override
+        public boolean match(String version) {
+            for (MatchRule matchRule : matchRules) {
+                if (!matchRule.match(version)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            for (MatchRule rule : matchRules) {
+                sb.append(rule.toString()).append(' ');
+            }
+            return sb.toString();
+        }
+    }
+
+    private static int[] toVersionInts(String version) {
+        String[] vers = StringUtils.split(version, '.');
+        int[] ints = new int[4];
+        for (int i = 0; i < ints.length; i++) {
+            if (vers.length > i) {
+                ints[i] = Integer.parseInt(vers[i]);
+            } else {
+                break;
+            }
+        }
+        return ints;
+    }
+
+    private static String trimVersion(String version) {
+        //remove '-SNAPSHOT'
+        int p = version.indexOf('-');
+        if (p > 0) {
+            version = version.substring(0, p);
+        }
+        return version;
+    }
+
+    private static VersionComparator getVersionComparator(String operator) {
+        if (operator.startsWith(">=")) {
+            return greaterThanOrEqualToComparator;
+        } else if (operator.startsWith(">")) {
+            return greaterThanComparator;
+        } else if (operator.startsWith("<=")) {
+            return lessThanOrEqualToComparator;
+        } else if (operator.startsWith("<")) {
+            return lessThanComparator;
+        }
+        throw new IllegalArgumentException("Comparison operator is invalid: 
"+operator);
+    }
+
+    private Pattern cmpExprPattern = Pattern.compile("<=|>=|<|>|[\\d\\.]+");
+    private MatchRule parseRangeMatchRule(String versionPattern) {
+        List<MatchRule> matchRules = new ArrayList<>();
+        Matcher matcher = cmpExprPattern.matcher(versionPattern);
+        while (matcher.find()) {
+            if (matchRules.size() == 2) {
+                throw new IllegalArgumentException("Invalid range match rule: 
"+versionPattern);
+            }
+            String operator = matcher.group();
+            if(!matcher.find()){
+                throw new IllegalArgumentException("Parse range match rule 
failed, unexpected EOF: "+versionPattern);
+            }
+            String version = matcher.group();
+            matchRules.add(new RangeMatchRule(operator, version));
+        }
+
+        if (matchRules.size() == 1) {
+            return matchRules.get(0);
+        } else if (matchRules.size() == 2) {
+            return new CombineMatchRule(matchRules);
+        }
+        throw new IllegalArgumentException("Parse range match rule failed: 
"+versionPattern);
+    }
+
+    private interface VersionComparator {
+        boolean match(int[] matchingVersionInts, int[] versionInts);
+    }
+
+    private static VersionComparator greaterThanComparator = new 
VersionComparator() {
+        @Override
+        public boolean match(int[] matchingVersionInts, int[] versionInts) {
+            for (int i = 0; i < versionInts.length; i++) {
+                if (matchingVersionInts[i] > versionInts[i]) {
+                    return true;
+                } else if (matchingVersionInts[i] < versionInts[i]) {
+                    return false;
+                }
+            }
+            return false;
+        }
+    };
+
+    private static VersionComparator greaterThanOrEqualToComparator = new 
VersionComparator() {
+        @Override
+        public boolean match(int[] matchingVersionInts, int[] versionInts) {
+            return Arrays.equals(matchingVersionInts, versionInts) ||
+                    greaterThanComparator.match(matchingVersionInts, 
versionInts);
+        }
+    };
+
+    private static VersionComparator lessThanComparator = new 
VersionComparator() {
+        @Override
+        public boolean match(int[] matchingVersionInts, int[] versionInts) {
+            for (int i = 0; i < versionInts.length; i++) {
+                if (matchingVersionInts[i] < versionInts[i]) {
+                    return true;
+                } else if (matchingVersionInts[i] > versionInts[i]) {
+                    return false;
+                }
+            }
+            return false;
+        }
+    };
+
+    private static VersionComparator lessThanOrEqualToComparator = new 
VersionComparator() {
+        @Override
+        public boolean match(int[] matchingVersionInts, int[] versionInts) {
+            return Arrays.equals(matchingVersionInts, versionInts) ||
+                    lessThanComparator.match(matchingVersionInts, versionInts);
+        }
+    };
+
 }
diff --git 
a/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java
 
b/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java
index b8f7483..c23ce27 100644
--- 
a/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java
+++ 
b/test/dubbo-scenario-builder/src/test/java/org/apache/dubbo/scenario/builder/VersionMatcherTest.java
@@ -41,10 +41,10 @@ public class VersionMatcherTest {
         candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
 
         String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 
-Dspring.version:4.1.13.RELEASE"));
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 
-Dspring.version:4.1.13.RELEASE"));
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 
-Dspring.version:5.3.2"));
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 
-Dspring.version:5.3.2"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.7 
-Dspring.version=4.1.13.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0 
-Dspring.version=4.1.13.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.7 
-Dspring.version=5.3.2"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0 
-Dspring.version=5.3.2"));
     }
 
     @Test
@@ -59,8 +59,8 @@ public class VersionMatcherTest {
         candidateVersions += "spring-boot.version:2.1.1.RELEASE";
 
         String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 
-Dspring-boot.version:2.1.1.RELEASE"));
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 
-Dspring-boot.version:2.1.1.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.7 
-Dspring-boot.version=2.1.1.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0 
-Dspring-boot.version=2.1.1.RELEASE"));
     }
 
     @Test
@@ -74,8 +74,212 @@ public class VersionMatcherTest {
         candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
 
         String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:2.7.7 
-Dspring-boot.version:2.0.8.RELEASE"));
-        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version:3.0 
-Dspring-boot.version:2.0.8.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.7 
-Dspring-boot.version=2.0.8.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0 
-Dspring-boot.version=2.0.8.RELEASE"));
+    }
+
+    @Test
+    public void testExcludeMatch() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= 2.7*, !2.7.9*, 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.8 
-Dspring-boot.version=2.0.8.RELEASE"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0.0 
-Dspring-boot.version=2.0.8.RELEASE"));
+        
Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.9-SNAPSHOT"));
+    }
+
+    @Test
+    public void testRangeMatch() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= >=2.7.7 <2.7.9, 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0.0"));
+        
Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.9-SNAPSHOT"));
+    }
+
+    @Test
+    public void testRangeMatch2() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= [ >= 2.7.7 < 2.7.9, 3.* ]\n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0.0"));
+        
Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.9-SNAPSHOT"));
+    }
+
+    @Test
+    public void testRangeMatch3() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= [ '<2.7.8', \">= 2.7.9\", 3.* ]\n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0.0"));
+        
Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.9-SNAPSHOT"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+    }
+
+    @Test
+    public void testRangeMatchException1() throws Exception {
+        String matchRule = ">= 2.7.7 < 2.7 .9";
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= " + matchRule + ", 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        try {
+            getVersionMatrix(caseVersionRules, candidateVersions);
+            Assert.fail("Invalid range match rule should not pass through");
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Invalid range match 
rule: " + matchRule));
+        }
+    }
+
+    @Test
+    public void testRangeMatchException2() throws Exception {
+        String matchRule = "'>= 2.7.7 < 2.7.9";
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= " + matchRule + ", 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        try {
+            getVersionMatrix(caseVersionRules, candidateVersions);
+            Assert.fail("Invalid range match rule should not pass through");
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Version match rule is 
invalid: " + matchRule));
+        }
+    }
+
+    @Test
+    public void testRangeMatchException3() throws Exception {
+        String matchRule = "\">= 2.7.7 < 2.7.9";
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= " + matchRule + ", 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        try {
+            getVersionMatrix(caseVersionRules, candidateVersions);
+            Assert.fail("Invalid range match rule should not pass through");
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Version match rule is 
invalid: " + matchRule));
+        }
+    }
+
+    @Test
+    public void testRangeMatchException4() throws Exception {
+        String matchRule = "\">= 2.7.7 < 2.7.9'";
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= " + matchRule + ", 3.* \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        try {
+            getVersionMatrix(caseVersionRules, candidateVersions);
+            Assert.fail("Invalid range match rule should not pass through");
+        } catch (Exception e) {
+            Assert.assertTrue(e.getMessage().contains("Version match rule is 
invalid: " + matchRule));
+        }
+    }
+
+    @Test
+    public void testGreaterThanOrEqualTo() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= >=2.7.9 \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        
Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.9-SNAPSHOT"));
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0.0"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+    }
+
+    @Test
+    public void testGreaterThan() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= >2.7.9 \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=3.0.0"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.9"));
+    }
+
+    @Test
+    public void testLessThan() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= <2.7.9 \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=3.0.0"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=2.7.9"));
+    }
+
+    @Test
+    public void testLessThanOrEqualTo() throws Exception {
+        String caseVersionRules = "# SpringBoot app\n" +
+                "dubbo.version= <=2.7.9 \n" +
+                "spring-boot.version= 2.0.8.RELEASE \n\n\n";
+
+        String candidateVersions = "dubbo.version:2.7.8,2.7.9-SNAPSHOT,3.0.0;";
+        candidateVersions += "spring.version:4.1.13.RELEASE,5.3.2;";
+        candidateVersions += 
"spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE;";
+
+        String versionMatrix = getVersionMatrix(caseVersionRules, 
candidateVersions);
+        Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.8"));
+        
Assert.assertTrue(versionMatrix.contains("-Ddubbo.version=2.7.9-SNAPSHOT"));
+        Assert.assertFalse(versionMatrix.contains("-Ddubbo.version=3.0.0"));
     }
 
     private String getVersionMatrix(String caseVersionRules, String 
candidateVersions) throws Exception {
diff --git a/test/quick-start_cn.md b/test/quick-start_cn.md
index 0d5da22..225fda6 100644
--- a/test/quick-start_cn.md
+++ b/test/quick-start_cn.md
@@ -4,8 +4,8 @@
 ### 构建测试镜像
 
 ```
-cd dubbo-samples/test
-./build-test-image.sh
+cd dubbo-samples
+./test/build-test-image.sh
 ```
 
 
如果构建镜像时apt更新数据很缓慢,可以通过设置环境变量`DEBIAN_MIRROR=http_mirror_server`来指定Debian镜像地址加快构建速度。
@@ -13,15 +13,15 @@ cd dubbo-samples/test
 
比如下面脚本指定使用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
+DEBIAN_MIRROR=http://mirrors.aliyun.com ./test/build-test-image.sh
 ```
 
 也可以执行封装好的脚本:
 
 ```
-cd dubbo-samples/test
-./build-test-image-use-aliyun-mirror.sh
+cd dubbo-samples
+./test/build-test-image-use-aliyun-mirror.sh
 ```
 
 ### 运行测试案例
@@ -37,19 +37,19 @@ cd dubbo-samples/test
 * 运行单个测试案例
 
   ```
-  ./run-tests.sh <project.basedir>
+  ./test/run-tests.sh <project.basedir>
   ```
   
   比如运行`dubbo-samples-annotation`测试案例:
   
   ```
-  ./run-tests.sh ../dubbo-samples-annotation
+  ./test/run-tests.sh dubbo-samples-annotation
   ```
   
 * 调试单个测试案例
 
   ```
-  DEBUG=service1,service2 ./run-tests.sh <project.basedir>
+  DEBUG=service1,service2 ./test/run-tests.sh <project.basedir>
   ```
 
   详细的调试方法,请参考"调试运行测试案例"小节。
@@ -57,13 +57,13 @@ cd dubbo-samples/test
 * 运行指定的测试案例列表
 
   ```
-  TEST_CASE_FILE=testcases1.txt ./run-tests.sh
+  TEST_CASE_FILE=testcases1.txt ./test/run-tests.sh
   ```
  
 * 运行全部测试案例
  
   ```
-   ./run-tests.sh
+   ./test/run-tests.sh
   ```
  
   run-tests.sh 运行全部测试案例的原理:
@@ -291,12 +291,61 @@ dubbo.version=2.7*, 3.*
 spring-boot.version=2.*
 ```
 
-**相关环境变量:**
+**关于版本匹配规则:**
 
-CANDIDATE_VERSIONS: 候选版本列表,格式请参考下面的例子。
+* 通配符匹配
 
-VERSIONS_LIMIT: 设置测试的版本数量限制,超过指定的数量则被截断丢弃。
+下面的规则匹配所有`2.7`开头的版本号,及`3.`开头的版本号:
 
+```
+  dubbo.version=2.7*, 3.*
+```  
+  
+* 具体的版本号
+
+下面的规则只匹配`2.7.8` 及 `2.7.9`,而不会匹配`2.7.8.1`:
+
+```
+  dubbo.version=2.7.8, 2.7.9
+```  
+
+* 范围匹配
+
+下面的规则匹配了小于2.7.8及大于2.7.9的版本,即可以匹配 `2.7.7`, `2.7.7.1`, `2.7.9`, 
`3.0`,但不会匹配`2.7.8`开头的版本:
+
+```
+  dubbo.version=[ <2.7.8, >=2.7.9 ]
+```
+
+下面的规则匹配了大于等于2.7.8且小于2.7.9区间所有版本,即可以匹配`2.7.8`, `2.7.8.1`, `2.7.8.2` 等:
+
+```
+  dubbo.version=[ ">=2.7.8 <2.7.9" ]
+```
+  
+
+* 排除版本
+
+  通配符及具体版本号前加上'!'表示为其排除规则,排除(exclude)规则优先级高于其它包含(include)规则。
+  
+  下面的匹配规则包含2.7开头的版本号,但排除了`2.7.8`:
+  
+  ```
+  dubbo.version=2.7.*, !2.7.8
+  ```
+  
+  下面的匹配规则包含2.7开头的版本号,但排除所有`2.7.8`开头的版本号,如 `2.7.8`, `2.7.8.1`:
+  ```
+  dubbo.version=2.7.*, !2.7.8*
+  ```
+    
+  
+**注意:**
+
+  如果指定了多个匹配规则,最终计算是或(OR)操作,只要满足一条规则就include/exclude该版本号。  
+
+
+**版本匹配错误:**
 
 除了dubbo/spring/spring-boot组件,其它有需要测试的组件也可以配置。
 如果要添加新的组件版本需要保证github 
workflows及`run-tests.sh`的`CANDIDATE_VERSIONS`环境变量包含该组件的候选版本,否则运行测试案例会报错如下:
@@ -305,6 +354,25 @@ VERSIONS_LIMIT: 设置测试的版本数量限制,超过指定的数量则被
 Component not match: dubbo.version, rules: [3.*]
 ```
 
+**关于候选版本环境变量:**
+
+* CANDIDATE_VERSIONS : 候选版本列表
+
+  格式为: <组件版本变量名1>=<版本1>[,版本2];<组件版本变量名2>=<版本2.1>[,版本2.2];..
+  
+  ```
+  export 
CANDIDATE_VERSIONS="dubbo.version:3.0.0-SNAPSHOT;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+  ```
+
+* DUBBO_VERSION: Dubbo版本列表 
+  
+  只修改Dubbo版本,其它组件使用默认值。
+  
+  ```
+    export DUBBO_VERSION="3.0.0-SNAPSHOT"
+  ```
+
+
 github workflows的候选版本配置格式如下,每行为一个组件的版本列表,也可以用不同的行指定组件不兼容的版本。
 如spring-boot 1.x 和 2.x 不兼容,可以在两行分别配置。
 
@@ -319,12 +387,6 @@ env:
     '
 ```
 
-本地开发测试`run-tests.sh`脚本的默认候选版本如下,只测试一个版本:
-
-```
-CANDIDATE_VERSIONS="dubbo.version:2.7.8;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
-```
-
 #### 本地测试dubbo 3.0的sample
 
 1、 checkout and build dubbo 3.0
@@ -353,33 +415,32 @@ spring.version=4.*, 5.*
 候选版本列表中指定dubbo.version为3.0的版本号
 
 ```
-export 
CANDIDATE_VERSIONS="dubbo.version:3.0.0-SNAPSHOT;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+export DUBBO_VERSION="3.0.0-SNAPSHOT"
 ```
-在同一个shell中,只需要执行一次 `export CANDIDATE_VERSIONS=...` 命令,后面多次执行测试案例都会生效。
+在同一个shell中,只需要执行一次 `export DUBBO_VERSION=...` 命令,后面多次执行测试案例都会生效。
 
 如果是测试 2.7.9-SNAPSHOT则设置为:
-
 ```
- export 
CANDIDATE_VERSIONS="dubbo.version:2.7.9-SNAPSHOT;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+export DUBBO_VERSION="2.7.9-SNAPSHOT"
 ```
 
 同时测试 2.7.8和2.7.9-SNAPSHOT则设置为:
 
 ```
- export 
CANDIDATE_VERSIONS="dubbo.version:2.7.8,2.7.9-SNAPSHOT;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+export DUBBO_VERSION="2.7.9-SNAPSHOT,2.7.8"
 ```
 
 4、启动测试案例
 
 ```
-cd dubbo-samples/test
-./run-test.sh ../dubbo-samples-xxxx
+cd dubbo-samples
+./test/run-test.sh dubbo-samples-xxxx
 ```
 
 ### 调试运行测试案例
 
   ```
-  DEBUG=service1,service2 ./run-tests.sh <project.basedir>
+  DEBUG=service1,service2 ./test/run-tests.sh <project.basedir>
   ```
 
   可以通过设置环境变量`DEBUG=service1,service2`来指定哪些app/test服务开启远程调试,自动分配debug端口,
@@ -389,13 +450,7 @@ cd dubbo-samples/test
     
   下面以`dubbo-samples-annotation`举例说明如何调试运行测试案例。
     
-  先用普通方式执行一次测试案例:
-  
-  ```
-  ./run-tests.sh ../dubbo-samples-annotation
-  ```
-  
-  
查看生成的`dubbo-samples-annotation/target/docker-compose.yml`,可知AnnotationProviderBootstrap的服务名称为`dubbo-samples-annotation`,
+  
查看case-configuration.yml配置,可知AnnotationProviderBootstrap的服务名称为`dubbo-samples-annotation`,
   test类的服务名为`dubbo-samples-annotation-test`。
   
   * **调试provider类:AnnotationProviderBootstrap**
@@ -403,7 +458,7 @@ cd dubbo-samples/test
     执行启动命令,以suspend模式启动AnnotationProviderBootstrap:
     
     ```
-    DEBUG=dubbo-samples-annotation ./run-tests.sh ../dubbo-samples-annotation
+    DEBUG=dubbo-samples-annotation ./test/run-tests.sh dubbo-samples-annotation
     ```
     
     直到可以看到下面的日志信息:
@@ -424,7 +479,7 @@ cd dubbo-samples/test
     执行启动命令,以suspend模式启动test:
     
     ```
-    DEBUG=dubbo-samples-annotation-test ./run-tests.sh 
../dubbo-samples-annotation
+    DEBUG=dubbo-samples-annotation-test ./test/run-tests.sh 
dubbo-samples-annotation
     ```
     
     直到可以看到下面的日志信息:
@@ -440,7 +495,13 @@ cd dubbo-samples/test
     执行调试启动命令
     
     ```
-    DEBUG=dubbo-samples-annotation,dubbo-samples-annotation-test 
./run-tests.sh ../dubbo-samples-annotation
+    DEBUG=dubbo-samples-annotation,dubbo-samples-annotation-test 
./test/run-tests.sh dubbo-samples-annotation
+    ```
+    
+    或者使用通配符:
+    
+    ```
+    DEBUG=dubbo* ./test/run-tests.sh dubbo-samples-annotation
     ```
     
     同时调试多个suspend方式启动的app/test服务,需要按照依赖顺序连接调试端口,保证前置服务启动成功后,才能继续调试后一个服务。
diff --git a/test/run-tests.sh b/test/run-tests.sh
index 637a55f..3d1cb10 100755
--- a/test/run-tests.sh
+++ b/test/run-tests.sh
@@ -1,32 +1,12 @@
 #!/bin/bash
 
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-# constants
-TEST_SUCCESS="TEST SUCCESS"
-TEST_FAILURE="TEST FAILURE"
-TEST_IGNORED="TEST IGNORED"
-
-ERROR_MSG_FLAG=":ErrorMsg:"
-
-# Exit codes
-# version matrix not match
-EXIT_UNMATCHED=100
-# ignore testing
-EXIT_IGNORED=120
-
-
-abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; 
esac; }
-
-trim() {
-    local var="$*"
-    # remove leading whitespace characters
-    var="${var#"${var%%[![:space:]]*}"}"
-    # remove trailing whitespace characters
-    var="${var%"${var##*[![:space:]]}"}"
-    printf '%s' "$var"
-}
+TEST_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+WORK_DIR="$(pwd)"
+echo "WorkDir: $WORK_DIR"
 
+#-----------------------------------#
+# environments
+#-----------------------------------#
 JAVA_VER=${JAVA_VER:-8}
 echo "JAVA_VER: $JAVA_VER"
 
@@ -40,97 +20,23 @@ echo "SHOW_ERROR_DETAIL: $SHOW_ERROR_DETAIL"
 maxForks=${FORK_COUNT:-2}
 echo "FORK_COUNT: $maxForks"
 
-
 #debug DEBUG=service1,service2
 #deubg all duboo-xxx: DEBUG=dubbo*
 export DEBUG=$DEBUG
 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=`abspath $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:$JAVA_VER"
-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
-
-
-# prepare testcases
-cd $DIR
-
-CONFIG_FILE="case-configuration.yml"
-VERSONS_FILE="case-versions.conf"
-
-mkdir -p $DIR/jobs
-testListFile=$DIR/jobs/testjob.txt
-targetTestcases=$1
-if [ "$targetTestcases" != "" ];then
-  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
-    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
-
-totalCount=`grep "" -c $testListFile`
-echo "Total test cases : $totalCount"
-
-if [ "$DEBUG" != "" ] && [ $totalCount -gt 1 ]; then
-  echo "Only one case can be debugged"
-  exit 1
-fi
-
-#clear test results
-testResultFile=${testListFile%.*}-result-java${JAVA_VER}.txt
-rm -f $testResultFile
-touch $testResultFile
-echo "Test results: $testResultFile"
-
+DUBBO_VERSION=${DUBBO_VERSION:-2.7.9-SNAPSHOT}
 if [ "$CANDIDATE_VERSIONS" == "" ];then
-  
CANDIDATE_VERSIONS="dubbo.version:2.7.8;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
-#  
CANDIDATE_VERSIONS="dubbo.version:2.7.8;spring.version:4.3.16.RELEASE,5.3.3;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+  
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;spring.version:4.3.16.RELEASE;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
+#  
CANDIDATE_VERSIONS="dubbo.version:2.7.9-SNAPSHOT;spring.version:4.3.16.RELEASE,5.3.3;spring-boot.version:1.5.13.RELEASE,2.1.1.RELEASE"
 fi
 export CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS
 echo "CANDIDATE_VERSIONS: ${CANDIDATE_VERSIONS[@]}"
 
 # test combination versions limit of single case
-VERSIONS_LIMIT=${VERSIONS_LIMIT:-4}
-export VERSIONS_LIMIT=$VERSIONS_LIMIT
-echo "VERSIONS_LIMIT: $VERSIONS_LIMIT"
-
+#VERSIONS_LIMIT=${VERSIONS_LIMIT:-4}
+#export VERSIONS_LIMIT=$VERSIONS_LIMIT
+#echo "VERSIONS_LIMIT: $VERSIONS_LIMIT"
 
 if [ "$MVN_OPTS" != "" ]; then
   export MVN_OPTS=$MVN_OPTS
@@ -144,6 +50,30 @@ export BUILD_OPTS=$BUILD_OPTS
 echo "BUILD_OPTS: $BUILD_OPTS"
 
 
+#-----------------------------------#
+# constants
+#-----------------------------------#
+TEST_SUCCESS="TEST SUCCESS"
+TEST_FAILURE="TEST FAILURE"
+TEST_IGNORED="TEST IGNORED"
+
+ERROR_MSG_FLAG=":ErrorMsg:"
+
+CONFIG_FILE="case-configuration.yml"
+VERSONS_FILE="case-versions.conf"
+
+# Exit codes
+# version matrix not match
+EXIT_UNMATCHED=100
+# ignore testing
+EXIT_IGNORED=120
+
+
+#-----------------------------------#
+# functions
+#-----------------------------------#
+abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; 
esac; }
+
 function get_error_msg() {
   log_file=$1
   error_msg=`grep $ERROR_MSG_FLAG $log_file`
@@ -166,6 +96,18 @@ function print_log_file() {
   fi
 }
 
+function check_test_image() {
+    #check dubbo/sample-test image and version
+    test_image="dubbo/sample-test:$JAVA_VER"
+    echo "Checking test image [$test_image] .. "
+    docker images --format 'table 
{{.Repository}}:{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}' | grep $test_image
+    result=$?
+    if [ $result != 0 ];then
+      echo "Test image not found: $test_image, please run 'bash 
./build-test-image.sh' first."
+      exit 1
+    fi
+}
+
 function process_case() {
   case_dir=$1
   case_no=$2
@@ -321,12 +263,73 @@ function process_case() {
   rm -f $project_home/*.log $project_home/version-matrix.*
 }
 
+
+#-----------------------------------#
+# main
+#-----------------------------------#
+#TEST_CASE_FILE
+if [ "$TEST_CASE_FILE" != "" ]; then
+  # convert relative path to absolute path
+  if [[ $TEST_CASE_FILE != /* ]]; then
+    TEST_CASE_FILE=`abspath $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"
+
+# prepare testcases
+mkdir -p $TEST_DIR/jobs
+testListFile=$TEST_DIR/jobs/testjob.txt
+targetTestcases=$1
+if [ "$targetTestcases" != "" ];then
+  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
+    testListFile=$TEST_CASE_FILE
+    if [ ! -f $testListFile ]; then
+      echo "Testcases file not found: $testListFile"
+      exit 1
+    fi
+  else
+    # find all case-configuration.yml
+    base_dir="$( dirname $TEST_DIR )"
+    rm -f $testListFile
+    echo "Searching all '$CONFIG_FILE' under dir $base_dir .."
+    find $base_dir -name $CONFIG_FILE | grep -v "$TEST_DIR" > $testListFile
+  fi
+fi
+
+totalCount=`grep "" -c $testListFile`
+echo "Total test cases : $totalCount"
+
+if [ "$DEBUG" != "" ] && [ $totalCount -gt 1 ]; then
+  echo "Only one case can be debugged"
+  exit 1
+fi
+
+#clear test results
+testResultFile=${testListFile%.*}-result-java${JAVA_VER}.txt
+rm -f $testResultFile
+touch $testResultFile
+echo "Test results: $testResultFile"
+
 # build scenario-builder
-SCENARIO_BUILDER_DIR=$DIR/dubbo-scenario-builder
+SCENARIO_BUILDER_DIR=$TEST_DIR/dubbo-scenario-builder
 echo "Building scenario builder .."
 cd $SCENARIO_BUILDER_DIR
 mvn $BUILD_OPTS &> $SCENARIO_BUILDER_DIR/mvn.log
 result=$?
+cd $WORK_DIR
 if [ $result -ne 0 ]; then
   echo "Build dubbo-scenario-builder failure, please check logs: 
$SCENARIO_BUILDER_DIR/mvn.log"
   cat $SCENARIO_BUILDER_DIR/mvn.log
@@ -342,9 +345,10 @@ else
   echo "Found test builder : $test_builder_jar"
 fi
 
+#check test image
+check_test_image
 
 # start run tests
-cd $DIR
 testStartTime=$SECONDS
 
 #counter


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to