TTCN中PTC的運行流程

一些概念

Component(測試組件或者測試成分),TTCN接觸下來最頻繁的就是MTC(Main Test Component,主測試組件),在執行測試用例前,需要首先創建一個MTC,在testcase運行過程中,只能有唯一的MTC。如果沒有指明testcase需要runs on在某個Component,系統默認的component就是MTC。在testcase代碼中,不能控制MTC的建立與停止。

非主測試組件的測試組件叫PTC(ParallelTest Component, 並行測試組件), PTC是由testcase控制的,最後由系統銷燬。testcase可以執行create,start,stop等操作 。

簡單說,一個PTC就可以理解爲TTCN模擬出來的一臺遠程主機的進程。通過它,模擬出其他主機實現並行測試。而測試組件之間,通過通信端口實現通信。


一個簡單的例子

這個testcase中,簡單執行:

telnet_IPworks();
//check if every port configuration is right
startClient(tsp_ptcClientName0);  //在這裏啓動名爲tsp_ptcClientName0的PTC
startClient(tsp_ptcClientName1);
startClient(tsp_ptcClientName2);
startClient(tsp_ptcClientName3);
startClient(tsp_ptcClientName4);

startClient(tsp_ptcClientName11);
…
sendCommand_byPTC("date ",tsp_ptcClientName11,2.2);


PCT和startClient的實現(common/CLI/CLI_Function.ttcn.linux):

//定義了接下來需要使用的PTC,類似C中的結構體概念
	type component PTC_CT
    	{
        	port TELNETasp_PT telnet_client_port; //與ipwork測試系統接口通信的端口
        	port ProcePort managePort; //與mtc通訊的端口

        	var BatchCommand tcv_batchCommand;

       	 	//if tcv_bcheckBatchResp== true ,check BatchCommad's Response from SUT ,or not
        	var boolean tcv_bcheckBatchResp := true;
    	}

	function startClient(charstring p_ClientName) runs on MTC_CT
    	{
        	//initial PTC
		//如果沒有初始化PTC的列表,則根據ipwork.cfg中定義的tsp_ptcClientName*名,初始化若干PTC備用

        	if(tcv_isPTCInitial == false)       	 	
                {
		// PTC_CT.create(tsp_ptcClientName0)建立一個名爲tsp_ptcClientName0的PTC,但不啓動
            		ptcClientName[0]:= PTC_CT.create(tsp_ptcClientName0);
            		ptcClientName[1]:= PTC_CT.create(tsp_ptcClientName1);
            		ptcClientName[2]:= PTC_CT.create(tsp_ptcClientName2);
            		ptcClientName[3]:= PTC_CT.create(tsp_ptcClientName3);
           		ptcClientName[4]:= PTC_CT.create(tsp_ptcClientName4);
            		ptcClientName[5]:= PTC_CT.create(tsp_ptcClientName5);
            		ptcClientName[6]:= PTC_CT.create(tsp_ptcClientName6);
            		ptcClientName[7]:= PTC_CT.create(tsp_ptcClientName7);
           		ptcClientName[8]:= PTC_CT.create(tsp_ptcClientName8);
            		ptcClientName[9]:= PTC_CT.create(tsp_ptcClientName9);
            		ptcClientName[10]:= PTC_CT.create(tsp_ptcClientName10);
           		ptcClientName[11]:= PTC_CT.create(tsp_ptcClientName11);
            		tcv_isPTCInitial := true; //have been intialed
        	}
		
		//獲取名爲p_ClientName的PTC引用p_ptcClient
        	var PTC_CT p_ptcClient := getCurrentPTC(p_ClientName);
log(getCurrentPTC(p_ClientName));
		
		//如果p_ptcClient已經停止運行
        	if(false == p_ptcClient.running)
        	{
			//利用map,將測試組件p_ptcClient映射到ipwork測試系統接口上,system是測試系統的組件引用
         		map(p_ptcClient:telnet_client_port,system:telnet_client_port);   
			//connect直接把p_ptcClient的端口managePort連接到mtc的managePort端口,
//這樣建立一條雙工的通信關係
          		connect(p_ptcClient:managePort,mtc:managePort);
			//啓動PTC引用p_ptcClient,啓動後執行CliSimulator()
          		p_ptcClient.start(CliSimulator());
          		pause(1.0);
       		 }        
        	 //sendCommand_byPTC("ipwcli",p_ClientName,0.2);
        	 //sendCommand_byPTC(tsp_user_admin,p_ClientName,0.2);
        	 //sendCommand_byPTC(tsp_adminpassword,p_ClientName,1.2);
}

startClient首先檢查PCT的存儲容器ptcClientName是否被初始化,如果沒有,則根據配置文件ipwork.cfg中設定的名字,create(兩個概念,這裏只是create,而不start)若干PCT引用填入ptcClientName備用。然後,根據參數p_ClientName獲取相應的PCT引用。

隨後,調用p_ptcClient.running檢測,p_ptcClient是否在運行(running運行在一個測試部件上檢查另一個測試部件是否運行,這裏實在mtc上檢查p_ptcClient)。如果沒有運行,則依次執行map和connect,map爲p_ptcClient與ipwork之間建立映射 ,connect爲mtc和p_ptcClient建立一個雙工的通信關係,即mtc的輸出口指向p_ptcClient的輸入口,p_ptcClient的輸出口指向mtc的輸入口。然後,執行p_ptcClient.start啓動PTC,PTC啓動後執行的就是start的參數CliSimulator(),如同pthread_create或者exec執行線程或進程函數一樣。

我們已經啓動了新的PTC,那麼看看p_ptcClient的CliSimulator()裏面究竟執行了那些東西:

function CliSimulator() runs on PTC_CT
{
      var charstring command := "";
      var charstring result := "";
      var charstring keyWords := "";
      timer t := 5.0;
      alt
      {
	//根據模板signature sig_Command(inout charstring p_Command),等待另一個測試組
//件的調用請求,遠程調用時傳入的參數p_Command將被賦予command。這裏的managePort就是
//之前mtc與p_ptcClient建立關聯的端口,那麼這裏就是等待mtc的調用
[]managePort.getcall(sig_Command:{?}) -> param(command)
            	{
			//根據mtc的command,telnet_client_port 即之前map建立的p_ptcClient與
//ipwork建立的關聯, telnet_client_port.send(command)將把mtc傳來的command轉發//給ipwork
                	telnet_client_port.send(command);                  	
repeat;
            	}

            	//Batch command operation
        []managePort.getcall(sig_BatchCommand:{?,?,?}) -param(tcv_batchCommand,keyWords,tcv_bcheckBatchResp)
            	{
                	var integer number := sizeof(tcv_batchCommand);
                	for(var integer i:=0;i<number;i:=i+1)
                	{
                    		telnet_client_port.send(tcv_batchCommand[i]);
                   		if(tcv_bcheckBatchResp == true)
                    		{
                        		t.start;    //啓動計時器
                        		alt
                       	 	{
						//接收到回覆
                            			[]telnet_client_port.receive(charstring:?) -> value result;                              		{
                                			
							//返回值與keyword比較
result := regexp(result,"*("&keyWords&")*",0);                                	t.stop;  //關閉計時器
							//錯誤結果
                                			if(result == "")
                                			{
                                    				log(tcv_batchCommand[i]," fail");
                                   				setverdict(fail);   //設置測試失敗
                                    				stop;      //停止當前component                	     
                                			}
                                			else if(result == keyWords)
                                			{
                                    				log("Execute command:",tcv_batchCommand[i]," success");
                               			 }

                            			}
                            			[]t.timeout       //超時
                                		{
                                    			log("Time out ,don't receive Response from SUT.fail");
                                    			setverdict(fail);
                                    			stop;
                            			}
                        	}
                        
                        	telnet_client_port.clear;
                        
                    	}
                }
		//調用sig_sendBatchcommandFinished,不等待,直接執行下一步

                managePort.call(sig_sendBatchcommandFinished:{},nowait);                
repeat;
                
            }
            []telnet_client_port.receive(charstring:?) -> value result
            {
                managePort.call(sig_Command:{result},nowait);
                repeat;    
            }
            []telnet_client_port.receive
            {
                repeat;
            }
            
        }
 }

這裏的alt是可選步,如同一個switch的消息循環,每個case選項或是等待遠程過程調用請求,或是等待接受數據,如果有請求或者數據傳輸,程序就會跳進對應的case,,這裏主要關心[]managePort.getcall(sig_Command:{?}) ->param(command)

getcall等待遠程的call,managePort就是之前mtc與p_ptcClient建立關聯的端口,那麼這裏就是等待mtc的call調用,根據module CLI_Signature中定義的函數原型signature sig_Command(inout charstring p_Command)mtc遠程call時傳入的參數p_Command將被賦予command,telnet_client_port 即之前map建立的p_ptcClient與ipwork建立的關聯, telnet_client_port.send(command)將把mtc傳來的command轉發給ipwork。這樣就完成了,從mtc傳送命令交由模擬的PTC轉發給ipwork測試系統接口的過程。下面的[]managePort.getcall(sig_BatchCommand也大體類似,只是將一串命令打包執行。

最後看下mtc中如何調用p_ptcClient的方法 ,使用sendCommand_byPTC("date ",tsp_ptcClientName11,2.2),它的作用就是通過名爲tsp_ptcClientName11的PTC發送date給ipwork:

function sendCommand_byPTC(charstring p_Command,charstring p_ClientName,float p_pause) runs on MTC_CT
{
        var PTC_CT p_ptcClient;
        p_ptcClient := getCurrentPTC(p_ClientName);   //獲取名爲p_ClientName的PTC引用
	//調用managePort通信的遠程方法,方法模板sig_Command,傳入參數p_Command
        managePort.call(sig_Command:{p_Command},nowait) to p_ptcClient;
        pause(p_pause);
}

這裏首先獲取了獲取名爲p_ClientName的PTC引用,然後利用managePort調用遠程方法(也就是mtc與p_ptcClient關聯的端口),這裏的遠程方法會到p_ptcClient中去找模板爲sig_Command的方法,也就是之前提到的CliSimulator()中相關內容。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章