TTCN中PTC的運(yùn)行流程
來源:程序員人生 發(fā)布時(shí)間:2014-09-26 20:03:59 閱讀次數(shù):2841次
一些概念
Component(測(cè)試組件或者測(cè)試成分),TTCN接觸下來最頻繁的就是MTC(Main Test Component,主測(cè)試組件),在執(zhí)行測(cè)試用例前,需要首先創(chuàng)建一個(gè)MTC,在testcase運(yùn)行過程中,只能有唯一的MTC。如果沒有指明testcase需要runs on在某個(gè)Component,系統(tǒng)默認(rèn)的component就是MTC。在testcase代碼中,不能控制MTC的建立與停止。
非主測(cè)試組件的測(cè)試組件叫PTC(ParallelTest Component, 并行測(cè)試組件), PTC是由testcase控制的,最后由系統(tǒng)銷毀。testcase可以執(zhí)行create,start,stop等操作 。
簡(jiǎn)單說,一個(gè)PTC就可以理解為TTCN模擬出來的一臺(tái)遠(yuǎn)程主機(jī)的進(jìn)程。通過它,模擬出其他主機(jī)實(shí)現(xiàn)并行測(cè)試。而測(cè)試組件之間,通過通信端口實(shí)現(xiàn)通信。
一個(gè)簡(jiǎn)單的例子
這個(gè)testcase中,簡(jiǎn)單執(zhí)行:
telnet_IPworks();
//check if every port configuration is right
startClient(tsp_ptcClientName0); //在這里啟動(dòng)名為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的實(shí)現(xiàn)(common/CLI/CLI_Function.ttcn.linux):
//定義了接下來需要使用的PTC,類似C中的結(jié)構(gòu)體概念
type component PTC_CT
{
port TELNETasp_PT telnet_client_port; //與ipwork測(cè)試系統(tǒng)接口通信的端口
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的列表,則根據(jù)ipwork.cfg中定義的tsp_ptcClientName*名,初始化若干PTC備用
if(tcv_isPTCInitial == false)
{
// PTC_CT.create(tsp_ptcClientName0)建立一個(gè)名為tsp_ptcClientName0的PTC,但不啟動(dòng)
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已經(jīng)停止運(yùn)行
if(false == p_ptcClient.running)
{
//利用map,將測(cè)試組件p_ptcClient映射到ipwork測(cè)試系統(tǒng)接口上,system是測(cè)試系統(tǒng)的組件引用
map(p_ptcClient:telnet_client_port,system:telnet_client_port);
//connect直接把p_ptcClient的端口managePort連接到mtc的managePort端口,
//這樣建立一條雙工的通信關(guān)系
connect(p_ptcClient:managePort,mtc:managePort);
//啟動(dòng)PTC引用p_ptcClient,啟動(dòng)后執(zhí)行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的存儲(chǔ)容器ptcClientName是否被初始化,如果沒有,則根據(jù)配置文件ipwork.cfg中設(shè)定的名字,create(兩個(gè)概念,這里只是create,而不start)若干PCT引用填入ptcClientName備用。然后,根據(jù)參數(shù)p_ClientName獲取相應(yīng)的PCT引用。
隨后,調(diào)用p_ptcClient.running檢測(cè),p_ptcClient是否在運(yùn)行(running運(yùn)行在一個(gè)測(cè)試部件上檢查另一個(gè)測(cè)試部件是否運(yùn)行,這里實(shí)在mtc上檢查p_ptcClient)。如果沒有運(yùn)行,則依次執(zhí)行map和connect,map為p_ptcClient與ipwork之間建立映射 ,connect為mtc和p_ptcClient建立一個(gè)雙工的通信關(guān)系,即mtc的輸出口指向p_ptcClient的輸入口,p_ptcClient的輸出口指向mtc的輸入口。然后,執(zhí)行p_ptcClient.start啟動(dòng)PTC,PTC啟動(dòng)后執(zhí)行的就是start的參數(shù)CliSimulator(),如同pthread_create或者exec執(zhí)行線程或進(jìn)程函數(shù)一樣。
我們已經(jīng)啟動(dòng)了新的PTC,那么看看p_ptcClient的CliSimulator()里面究竟執(zhí)行了那些東西:
function CliSimulator() runs on PTC_CT
{
var charstring command := "";
var charstring result := "";
var charstring keyWords := "";
timer t := 5.0;
alt
{
//根據(jù)模板signature sig_Command(inout charstring p_Command),等待另一個(gè)測(cè)試組
//件的調(diào)用請(qǐng)求,遠(yuǎn)程調(diào)用時(shí)傳入的參數(shù)p_Command將被賦予command。這里的managePort就是
//之前mtc與p_ptcClient建立關(guān)聯(lián)的端口,那么這里就是等待mtc的調(diào)用
[]managePort.getcall(sig_Command:{?}) -> param(command)
{
//根據(jù)mtc的command,telnet_client_port 即之前map建立的p_ptcClient與
//ipwork建立的關(guān)聯(lián), telnet_client_port.send(command)將把mtc傳來的command轉(zhuǎn)發(fā)//給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; //啟動(dòng)計(jì)時(shí)器
alt
{
//接收到回復(fù)
[]telnet_client_port.receive(charstring:?) -> value result; {
//返回值與keyword比較
result := regexp(result,"*("&keyWords&")*",0); t.stop; //關(guān)閉計(jì)時(shí)器
//錯(cuò)誤結(jié)果
if(result == "")
{
log(tcv_batchCommand[i]," fail");
setverdict(fail); //設(shè)置測(cè)試失敗
stop; //停止當(dāng)前component
}
else if(result == keyWords)
{
log("Execute command:",tcv_batchCommand[i]," success");
}
}
[]t.timeout //超時(shí)
{
log("Time out ,don't receive Response from SUT.fail");
setverdict(fail);
stop;
}
}
telnet_client_port.clear;
}
}
//調(diào)用sig_sendBatchcommandFinished,不等待,直接執(zhí)行下一步
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是可選步,如同一個(gè)switch的消息循環(huán),每個(gè)case選項(xiàng)或是等待遠(yuǎn)程過程調(diào)用請(qǐng)求,或是等待接受數(shù)據(jù),如果有請(qǐng)求或者數(shù)據(jù)傳輸,程序就會(huì)跳進(jìn)對(duì)應(yīng)的case,,這里主要關(guān)心[]managePort.getcall(sig_Command:{?}) ->param(command)
getcall等待遠(yuǎn)程的call,managePort就是之前mtc與p_ptcClient建立關(guān)聯(lián)的端口,那么這里就是等待mtc的call調(diào)用,根據(jù)module CLI_Signature中定義的函數(shù)原型signature sig_Command(inout charstring p_Command),mtc遠(yuǎn)程call時(shí)傳入的參數(shù)p_Command將被賦予command,telnet_client_port
即之前map建立的p_ptcClient與ipwork建立的關(guān)聯(lián), telnet_client_port.send(command)將把mtc傳來的command轉(zhuǎn)發(fā)給ipwork。這樣就完成了,從mtc傳送命令交由模擬的PTC轉(zhuǎn)發(fā)給ipwork測(cè)試系統(tǒng)接口的過程。下面的[]managePort.getcall(sig_BatchCommand也大體類似,只是將一串命令打包執(zhí)行。
最后看下mtc中如何調(diào)用p_ptcClient的方法 ,使用sendCommand_byPTC("date ",tsp_ptcClientName11,2.2),它的作用就是通過名為tsp_ptcClientName11的PTC發(fā)送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引用
//調(diào)用managePort通信的遠(yuǎn)程方法,方法模板sig_Command,傳入?yún)?shù)p_Command
managePort.call(sig_Command:{p_Command},nowait) to p_ptcClient;
pause(p_pause);
}
這里首先獲取了獲取名為p_ClientName的PTC引用,然后利用managePort調(diào)用遠(yuǎn)程方法(也就是mtc與p_ptcClient關(guān)聯(lián)的端口),這里的遠(yuǎn)程方法會(huì)到p_ptcClient中去找模板為sig_Command的方法,也就是之前提到的CliSimulator()中相關(guān)內(nèi)容。
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)