Tars | 第7篇 TarsJava Subset最終程式碼的測試方案設計

多氯環己烷 發表於 2021-09-14
Java


前言

中期彙報會後,對Tars Subset功能更加熟悉,並根據TarsGo的實現方式,對Java JDK實現程式碼進行翻新改造。於是有了以下兩篇分析文章:

第5篇 基於TarsGo Subset路由規則的Java JDK實現方式(上篇)
https://www.cnblogs.com/dlhjw/p/15245113.html

第6篇 基於TarsGo Subset路由規則的Java JDK實現方式(下篇)
https://www.cnblogs.com/dlhjw/p/15245116.html

其中,《上篇》注重TarsGo分析,《下篇》注重TarsJava實現方式。不出意外的話,最終提交的考核成果就在下面的GitHub程式碼倉庫中(以下簡稱“最終程式碼”),後續可能會有些許地方需要更改:

TarsJava 實現Subset路由規則JDK GitHub開源地址
https://github.com/dlhjw/TarsJava/commit/cc2fe884ecbe8455a8e1f141e21341f4f3dd98a3

最終程式碼與中期程式碼在整體思想邏輯上都是一致的都是:先判斷Subset路由規則,再根據規則路由到定義的節點。不同點在於:中期在處理整個過程時,用一個方法filterEndpointsBySubset()實現;而最終的實現方式則是以subsetEndpointFilter()方法作為整個Subset流量路由的入口,通過subsetManager管理器呼叫getSubset()方法獲取到路由規則的String型別的subset欄位,與節點自身的subset欄位一一比較過濾節點;其中Subset路由規則的判斷封裝在getSubset()方法裡;

總的來說就是最終程式碼是在處理subset規則邏輯中增加了很多細節,比如:通過新增的registry介面獲取subsetConf配置項;將獲取到是配置項存入快取中;以及將“判斷Subset路由規則”進行層層封裝,最終返回一個簡單的String型別的subset欄位與節點自身的subset欄位比較等;

因此,在測試方案上相比較中期有些許區別,但總體上的單元測試原則是不變的:

  1. 首先構建前置條件;
  2. 呼叫測試方法;
  3. 輸出測試結果;

其中的區別主要體現在前置條件的構建上,本篇將結合最終程式碼的實現邏輯,重點介紹其測試方案的設計;首先介紹測試方案的設計原則,接著針對五種情況(按比例單次、按比例多次、按引數精確、按引數正則路由與預設規則)做詳細介紹與展示測試結果。

最終程式碼的Subset執行流程分析請參考下面這篇文章:

第8篇 TarsJava Subset最終程式碼的執行流程與原理分析
https://blog.csdn.net/dlhjw1412/article/details/119932752

《測試方案設計》與《執行流程分析》兩篇文章相輔相成,相互觀閱能更快更好地理解整個Subset的業務流程與輸出示例;


1. SubsetConf配置項的結構

在中期,筆者使用一個map來模擬subset的流量規則;而在最終程式碼裡,是用多個物件來模擬Subset的配置,這些物件是理解整個Subset流量過濾規則的基礎的,因此很有必要在這裡做個介紹;

1.1 SubsetConf

public class SubsetConf {
    private boolean enanle;
    private String ruleType;
    private RatioConfig ratioConf;
    private KeyConfig keyConf;
    private Instant lastUpdate;
    ……
}

可以看出SubsetConf配置項裡有以下屬性:

  • enanle:表示是否開啟Subset流量管理功能;
    • true:開啟;false:關閉;
  • ruleType:表示流量管理的型別;
    • 目前有ratio按比例和key按引數兩種模式;
  • RatioConfig:表示按比例路由配置項;
    • 裡面定義了路由比例與路徑等資訊,詳情請參考《1.2 RatioConfig》
  • KeyConfig:表示按引數路由配置項;
    • 裡面定義了規則key與路由路徑等資訊,詳情請參考《1.3 KeyConfig》
  • lastUpdate:表示該配置項上次更新時間,將在快取那裡起作用;

1.2 RatioConfig

public class RatioConfig {
    private Map<String, Integer> rules;
    ……
}

RatioConfig裡只有一個map型別的rules路由規則,其中key為一個String型別的subset欄位,用來跟節點的subset欄位匹配,value為路由權重,如:{ {"v1" , 20} , {"v2" , 60} , {"v3" , 20} }表示路由到subset欄位為v1的節點的概率為0.2;路由到subset欄位為v2的節點的概率為0.6;路由到subset欄位為v3的節點的概率為0.2;

1.3 KeyConfig

public class KeyConfig {
    private String defaultRoute;
    private List<KeyRoute> rules;
    ……
}    

KeyConfig裡有兩個屬性,一個是defaultRoute預設路由路徑;另一個是list型別的rules,裡面是KeyRoute,其定義了按引數匹配的型別、規則key與路徑,詳情請見《1.4 KeyRoute》

1.4 KeyRoute

public class KeyRoute {
    private String action = null;
    private String value = null;
    private String route = null;
    public static final String TARS_ROUTE_KEY = "TARS_ROUTE_KEY";
    ……
}

KeyRoute裡面有四個String型別的屬性,如下:

  • action:用來定義引數匹配的型別;
    • 目前可設定的型別有:equals精確匹配、match正則匹配、default預設匹配;
  • value:這就是大名鼎鼎的規則key了。當action=equals時,還需滿足規則key與請求key匹配,才能進行精確匹配;當action=match時,還需滿足規則key與請求key正則匹配,才能進行正則匹配;action=default對規則key沒要求;
  • route:用來規定路由路徑,其值為一個String型別的subset欄位,匹配到節點的subset欄位;
  • TARS_ROUTE_KEY:一個常量欄位,為Tars請求體裡的status(map型別)的key;

1.5 SubsetConf的結構示意圖

上述提到的配置類聯絡結構圖如下:
SubsetConf結構圖

2. 測試方案設計

這裡的測試主要指測試subsetEndpointFilter()根據subset過濾節點這一核心方法,在測試中構建前置條件最為複雜,因此將在2.1仔細介紹;

2.1 構建前置條件

從SubsetConf的結構圖可以看出,按比例與引數路由的一些前置條件不同,比如按引數路由需要一個list型別的KeyRoute,而按比例路由則是用一個map型別的資料結構實現類似KeyRoute的功能;

除此之外,KeyRoute裡的value為規則的key,其作用是與請求key做對比匹配,是引數匹配的必要不充分條件;這就要求構建前置條件時要考慮從Tars的請求體TarsServantRequest中的status屬性(map型別)獲取到鍵TARS_ROUTE_KEY的值value,而Tars的請求體又要通過分散式上下文資訊DistributedContext獲取;預設路由又不用考慮染色key……

因此,按比例與預設路由方式的前置條件包括:

  • 一個Subset過濾器;
  • 核心方法subsetEndpointFilter的傳入引數;
    • objectName:物件名;
    • routeKey:上下文的染色key;
    • activeEp:存活的節點列表及存活的節點;
  • 一個SubsetManager管理器;
  • RatioConfig比例路由規則;
  • subsetConf配置項;
  • 等;

可以通過以下程式碼實現、模擬:

 //建立Subset過濾器
Subset subsetFilter = new Subset();
//模擬objectName
String objectName = "objectName";
//模擬routeKey
String routeKey = "routeKey";
//存活節點list列表
List<EndpointF> endpointFList = new ArrayList<EndpointF>();
Holder<List<EndpointF>> activeEp = new Holder<List<EndpointF>>(new ArrayList<EndpointF>());

//1. 給過濾器設定過濾規則
//1.1 建立SubsetManager管理器
 SubsetManager subsetManager = new SubsetManager();

 //1.1 設定比例路由規則
 RatioConfig ratioConf = new RatioConfig();
 Map<String , Integer> map = new HashMap<>();
 map.put("v1",20);
 map.put("v2",80);
 //map.put("v3",20);
 ratioConf.setRules(map);

 //1.2 設定subsetConf,並加入快取
 SubsetConf subsetConf = new SubsetConf();
 subsetConf.setEnanle(true);
 subsetConf.setRuleType("ratio");
 subsetConf.setRatioConf(ratioConf);
 subsetConf.setLastUpdate( Instant.now() );

 Map<String, SubsetConf> cache = new HashMap<>();
 cache.put(objectName,subsetConf);
 subsetManager.setCache(cache);

 //1.3 給過濾器設定過濾規則和管理者
 subsetFilter.setSubsetConf(subsetConf);
 subsetFilter.setSubsetManager(subsetManager);

 //2. 模擬存活節點
 endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
 endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
 endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
 endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
 endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
 endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
 activeEp.setValue(endpointFList);

而按引數匹配路由方式的前置條件包括:

  • 一個Subset過濾器;
  • 核心方法subsetEndpointFilter的傳入引數;
    • objectName:物件名;
    • routeKey:上下文的染色key;
    • activeEp:存活的節點列表及存活的節點;
  • 一個SubsetManager管理器;
  • KeyConfig引數路由規則;
  • KeyRoute引數路由屬性;
  • subsetConf配置項;
  • Tars的請求體TarsServantRequest;
  • 一個Session域,用來構建Tars請求體
  • 分散式上下文資訊DistributedContext;
  • 等;

可以通過以下程式碼實現、模擬:

//建立Subset過濾器
Subset subsetFilter = new Subset();
//模擬objectName
String objectName = "objectName";
//模擬routeKey
String routeKey = "routeKey";
//存活節點list列表
List<EndpointF> endpointFList = new ArrayList<EndpointF>();
Holder<List<EndpointF>> activeEp = new Holder<List<EndpointF>>(new ArrayList<EndpointF>());
//定義一個Session域,用來構建Tars請求體
Session session;

//1. 給過濾器設定過濾規則
//1.1 建立SubsetManager管理器
SubsetManager subsetManager = new SubsetManager();

//1.1 設定引數路由規則,這裡的KeyRoute的value為 “規則的染色key”
KeyConfig keyConf = new KeyConfig();
List<KeyRoute> krs = new LinkedList<>();
krs.add(new KeyRoute("match","routeKey","v1"));
keyConf.setRules(krs);

//1.2 設定subsetConf,並加入快取
SubsetConf subsetConf = new SubsetConf();
subsetConf.setEnanle(true);
subsetConf.setRuleType("key");
subsetConf.setKeyConf(keyConf);
subsetConf.setLastUpdate( Instant.now() );

Map<String, SubsetConf> cache = new HashMap<>();
cache.put(objectName,subsetConf);
subsetManager.setCache(cache);

//1.3 給過濾器設定過濾規則和管理者
subsetFilter.setSubsetConf(subsetConf);
subsetFilter.setSubsetManager(subsetManager);

//1.4 模擬Tars “請求的染色key” TARS_ROUTE_KEY,但請求染色key和規則染色key匹配時,才能精確路由
//1.4.1 建立Tars的請求體TarsServantRequest
TarsServantRequest request = new TarsServantRequest( session );
//1.4.2 往請求體的status新增{TARS_ROUTE_KEY, "routeKey"}鍵值對
Map<String, String> status = new HashMap<>();
status.put("TARS_ROUTE_KEY", "routeKey");
request.setStatus(status);
//1.4.3 構建分散式上下文資訊,將請求放入分散式上下文資訊中,因為getSubset()的邏輯是從分散式上下文資訊中取
DistributedContext distributedContext = new DistributedContextImpl();
distributedContext.put(DyeingSwitch.REQ,request);

//2. 模擬存活節點
endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
activeEp.setValue(endpointFList);

2.2 呼叫測試方法

呼叫測試方法比較簡單,用如下語句實現即可:

//4. 對存活節點按subset規則過濾
Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);

2.3 輸出測試結果

輸出測試結果也比較簡單,在過濾前後都遍歷一些節點列表,判斷其是否起到過濾功能即可,可以用如下程式碼實現:

//3. 輸出過濾前資訊
System.out.println("過濾前節點資訊如下:");
for( EndpointF endpoint : endpointFList){
    System.out.println(endpoint.toString());
}

//5. 輸出過濾結果
System.out.println("過濾後節點資訊如下:");
for( EndpointF endpoint : filterActiveEp.getValue() ){
    System.out.println(endpoint.toString());
}

如此,一個大概的測試方案就成型了,下面將介紹各路由方式的測試程式碼與測試結果;


3. 按比例路由規則 - 單次測試

測試程式碼如下

/**
 * 按比例路由規則 - 單次測試
 * 沒有測試registry獲取subsetConf功能
 */
@Test
public void testRatioOnce() {

    //1. 給過濾器設定過濾規則
    //1.1 建立SubsetManager管理器
    SubsetManager subsetManager = new SubsetManager();


    //1.1 設定比例路由規則
    RatioConfig ratioConf = new RatioConfig();
    Map<String , Integer> map = new HashMap<>();
    map.put("v1",20);
    map.put("v2",80);
    //map.put("v3",20);
    ratioConf.setRules(map);

    //1.2 設定subsetConf,並加入快取
    SubsetConf subsetConf = new SubsetConf();
    subsetConf.setEnanle(true);
    subsetConf.setRuleType("ratio");
    subsetConf.setRatioConf(ratioConf);
    subsetConf.setLastUpdate( Instant.now() );

    Map<String, SubsetConf> cache = new HashMap<>();
    cache.put(objectName,subsetConf);
    subsetManager.setCache(cache);

    //1.3 給過濾器設定過濾規則和管理者
    subsetFilter.setSubsetConf(subsetConf);
    subsetFilter.setSubsetManager(subsetManager);
    
    //2. 模擬存活節點
    endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
    activeEp.setValue(endpointFList);


    //3. 輸出過濾前資訊
    System.out.println("過濾前節點資訊如下:");
    for( EndpointF endpoint : endpointFList){
        System.out.println(endpoint.toString());
    }

    //4. 對存活節點按subset規則過濾
    Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);

    //5. 輸出過濾結果

    System.out.println("過濾後節點資訊如下:");
    for( EndpointF endpoint : filterActiveEp.getValue() ){
        System.out.println(endpoint.toString());
    }
}

測試結果如下

測試結果

在上述情況下,如果我們將所有v2節點刪除,即模擬經過按比例權重查詢後匹配到節點subset欄位為v2集合,但原來存活節點裡卻沒有subset欄位為v2的節點這種情況,將會輸出一句錯誤資訊,如下:

沒有符合要求的節點


4. 按比例路由規則 - 多次測試

測試程式碼如下

/**
 * 按比例路由規則 - 多次測試
 * 沒有測試registry獲取subsetConf功能
 */
@Test
public void testRatioTimes() {

    //1. 給過濾器設定過濾規則
    //1.1 建立SubsetManager管理器
    SubsetManager subsetManager = new SubsetManager();

    //1.1 設定比例路由規則
    RatioConfig ratioConf = new RatioConfig();
    Map<String , Integer> map = new HashMap<>();
    map.put("v1",20);
    map.put("v2",80);
    map.put("v3",20);
    ratioConf.setRules(map);

    //1.2 設定subsetConf,並加入快取
    SubsetConf subsetConf = new SubsetConf();
    subsetConf.setEnanle(true);
    subsetConf.setRuleType("ratio");
    subsetConf.setRatioConf(ratioConf);
    subsetConf.setLastUpdate( Instant.now() );

    Map<String, SubsetConf> cache = new HashMap<>();
    cache.put(objectName,subsetConf);
    subsetManager.setCache(cache);

    //1.3 給過濾器設定過濾規則和管理者
    subsetFilter.setSubsetConf(subsetConf);
    subsetFilter.setSubsetManager(subsetManager);

    //2. 模擬存活節點
    endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
    activeEp.setValue(endpointFList);


    //3. 迴圈times次
    int times = 1000000;
    int v1Times = 0;
    int v2Times = 0;
    int v3Times = 0;
    int errTimes = 0;
    for (int i = 0; i < times; i++) {
        //對存活節點按subset規則過濾
        Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);
        String subsetValue = filterActiveEp.getValue().get(0).getSubset();
        if("v1".equals(subsetValue)){
            v1Times++;
        } else if("v2".equals(subsetValue)){
            v2Times++;
        } else if("v3".equals(subsetValue)){
            v3Times++;
        } else {
            errTimes++;
        }

    }
    //輸出結果
    System.out.println("一共迴圈次數:" + times);
    System.out.println("路由到v1次數:" + v1Times);
    System.out.println("路由到v2次數:" + v2Times);
    System.out.println("路由到v3次數:" + v3Times);
    System.out.println("路由異常次數:" + errTimes);
}

測試結果如下

測試結果
這裡如果我們將語句subsetConf.setEnanle(true);中的true置為false,可以發現沒有起到路由功能,所有結點路由到v1那邊,如下圖所示:

沒有起到路由功能

如果我們給方法subsetEndpointFilter(objectName, routeKey, activeEp)中的routeKey傳入引數為空字串"",則會等比例隨機路由,測試結果如下:

等比例隨機路由


5. 按引數路由規則 - 精確匹配測試

測試程式碼如下

/**
 * 測試引數匹配 - 精確匹配
 * 沒有測試registry獲取subsetConf功能
 * 注意要成功必須routeKey和match匹配上
 */
@Test
public void testMatch() {

    //1. 給過濾器設定過濾規則
    //1.1 建立SubsetManager管理器
    SubsetManager subsetManager = new SubsetManager();


    //1.1 設定引數路由規則,這裡的KeyRoute的value為 “規則的染色key”
    KeyConfig keyConf = new KeyConfig();
    List<KeyRoute> krs = new LinkedList<>();
    krs.add(new KeyRoute("match","routeKey","v1"));
    keyConf.setRules(krs);

    //1.2 設定subsetConf,並加入快取
    SubsetConf subsetConf = new SubsetConf();
    subsetConf.setEnanle(true);
    subsetConf.setRuleType("key");
    subsetConf.setKeyConf(keyConf);
    subsetConf.setLastUpdate( Instant.now() );

    Map<String, SubsetConf> cache = new HashMap<>();
    cache.put(objectName,subsetConf);
    subsetManager.setCache(cache);

    //1.3 給過濾器設定過濾規則和管理者
    subsetFilter.setSubsetConf(subsetConf);
    subsetFilter.setSubsetManager(subsetManager);

    //1.4 模擬Tars “請求的染色key” TARS_ROUTE_KEY,但請求染色key和規則染色key匹配時,才能精確路由
    //1.4.1 建立Tars的請求體TarsServantRequest
    TarsServantRequest request = new TarsServantRequest( session );
    //1.4.2 往請求體的status新增{TARS_ROUTE_KEY, "routeKey"}鍵值對
    Map<String, String> status = new HashMap<>();
    status.put("TARS_ROUTE_KEY", "routeKey");
    request.setStatus(status);
    //1.4.3 構建分散式上下文資訊,將請求放入分散式上下文資訊中,因為getSubset()的邏輯是從分散式上下文資訊中取
    DistributedContext distributedContext = new DistributedContextImpl();
    distributedContext.put(DyeingSwitch.REQ,request);

    //2. 模擬存活節點
    endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
    activeEp.setValue(endpointFList);


    //3. 輸出過濾前資訊
    System.out.println("過濾前節點資訊如下:");
    for( EndpointF endpoint : endpointFList){
        System.out.println(endpoint.toString());
    }

    //4. 對存活節點按subset規則過濾
    Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);

    //5. 輸出過濾結果

    System.out.println("過濾後節點資訊如下:");
    for( EndpointF endpoint : filterActiveEp.getValue() ){
        System.out.println(endpoint.toString());
    }
}

測試結果如下

測試結果
這裡如果我們使規則key與請求key不匹配,將起不到過濾功能,並輸出一句錯誤日誌,如下圖所示:

精確匹配失敗


6. 按引數路由規則 - 正則匹配測試

測試程式碼如下

/**
 * 測試引數匹配 - 正則匹配
 * 沒有測試registry獲取subsetConf功能
 * 注意要成功必須routeKey和match匹配上
 */
@Test
public void testEqual() {

    //1. 給過濾器設定過濾規則
    //1.1 建立SubsetManager管理器
    SubsetManager subsetManager = new SubsetManager();


    //1.1 設定引數路由規則,這裡的KeyRoute的value為 “規則的染色key”
    KeyConfig keyConf = new KeyConfig();
    List<KeyRoute> krs = new LinkedList<>();
    krs.add(new KeyRoute("equal","routeKey","v1"));
    keyConf.setRules(krs);

    //1.2 設定subsetConf,並加入快取
    SubsetConf subsetConf = new SubsetConf();
    subsetConf.setEnanle(true);
    subsetConf.setRuleType("key");
    subsetConf.setKeyConf(keyConf);
    subsetConf.setLastUpdate( Instant.now() );

    Map<String, SubsetConf> cache = new HashMap<>();
    cache.put(objectName,subsetConf);
    subsetManager.setCache(cache);

    //1.3 給過濾器設定過濾規則和管理者
    subsetFilter.setSubsetConf(subsetConf);
    subsetFilter.setSubsetManager(subsetManager);

    //1.4 模擬Tars “請求的染色key” TARS_ROUTE_KEY,但請求染色key和規則染色key匹配時,才能精確路由
    //1.4.1 建立Tars的請求體TarsServantRequest
    TarsServantRequest request = new TarsServantRequest( session );
    //1.4.2 往請求體的status新增{TARS_ROUTE_KEY, "routeKey"}鍵值對
    Map<String, String> status = new HashMap<>();
    status.put("TARS_ROUTE_KEY", "route*");
    request.setStatus(status);
    //1.4.3 構建分散式上下文資訊,將請求放入分散式上下文資訊中,因為getSubset()的邏輯是從分散式上下文資訊中取
    DistributedContext distributedContext = new DistributedContextImpl();
    distributedContext.put(DyeingSwitch.REQ,request);

    //2. 模擬存活節點
    endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
    activeEp.setValue(endpointFList);


    //3. 輸出過濾前資訊
    System.out.println("過濾前節點資訊如下:");
    for( EndpointF endpoint : endpointFList){
        System.out.println(endpoint.toString());
    }

    //4. 對存活節點按subset規則過濾
    Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);

    //5. 輸出過濾結果

    System.out.println("過濾後節點資訊如下:");
    for( EndpointF endpoint : filterActiveEp.getValue() ){
        System.out.println(endpoint.toString());
    }
}

測試結果如下

測試結果

這裡如果我們使規則key與請求key正則匹配不上,跟精確匹配一樣將起不到過濾功能,並輸出一句錯誤日誌,如下圖所示:

正則匹配失敗


7. 無路由規則測試

測試程式碼如下

/**
 * 測試預設路由
 * 沒有測試registry獲取subsetConf功能
 */
@Test
public void testDefault() {

    //1. 給過濾器設定過濾規則
    //1.1 建立SubsetManager管理器
    SubsetManager subsetManager = new SubsetManager();


    //1.1 設定引數路由規則,這裡的KeyRoute的value為 “規則的染色key”
    KeyConfig keyConf = new KeyConfig();
    List<KeyRoute> krs = new LinkedList<>();
    krs.add(new KeyRoute("default","","v1"));
    keyConf.setRules(krs);

    //1.2 設定subsetConf,並加入快取
    SubsetConf subsetConf = new SubsetConf();
    subsetConf.setEnanle(true);
    subsetConf.setRuleType("key");
    subsetConf.setKeyConf(keyConf);
    subsetConf.setLastUpdate( Instant.now() );

    Map<String, SubsetConf> cache = new HashMap<>();
    cache.put(objectName,subsetConf);
    subsetManager.setCache(cache);

    //1.3 給過濾器設定過濾規則和管理者
    subsetFilter.setSubsetConf(subsetConf);
    subsetFilter.setSubsetManager(subsetManager);

    //2. 模擬存活節點
    endpointFList.add(new EndpointF("host1",1,2,3,4,5,6,"setId1",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host2",1,2,3,4,5,6,"setId2",7,8,9,10,"v1"));
    endpointFList.add(new EndpointF("host3",1,2,3,4,5,6,"setId3",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host4",1,2,3,4,5,6,"setId4",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v2"));
    endpointFList.add(new EndpointF("host5",1,2,3,4,5,6,"setId5",7,8,9,10,"v3"));
    activeEp.setValue(endpointFList);


    //3. 輸出過濾前資訊
    System.out.println("過濾前節點資訊如下:");
    for( EndpointF endpoint : endpointFList){
        System.out.println(endpoint.toString());
    }

    //4. 對存活節點按subset規則過濾
    Holder<List<EndpointF>> filterActiveEp = subsetFilter.subsetEndpointFilter(objectName, routeKey, activeEp);

    //5. 輸出過濾結果

    System.out.println("過濾後節點資訊如下:");
    for( EndpointF endpoint : filterActiveEp.getValue() ){
        System.out.println(endpoint.toString());
    }
}

測試結果如下

測試結果



最後

新人制作,如有錯誤,歡迎指出,感激不盡!
歡迎關注公眾號,會分享一些更日常的東西!
如需轉載,請標註出處!
Tars | 第7篇 TarsJava Subset最終程式碼的測試方案設計