如何Debug Hook脚本?
ClearQuest自带了一个名为dbwin32.exe的工具,在ClearQuest安装目录下。其可用于显示调用Session类的OutputDebugString()方法输出的文本,以及其他一些ClearQuest的一些输出信息。如果想跟踪hook的执行情况,则启动这个工具即可收集这些输出信息。
如果想让dbwin32.exe输出较详细的信息,需要在Windows注册表以下位置添加一个类型为REG_DWORD的键HookDebug: My Computer \HKEY_CURRENT_USER \Software \Rational Software \ClearQuest \<version id> \Common \ 设置这个键的值为1。
假设我们在某一个hook中定义了如下代码:
$session->OutputDebugString("\nOpenning exported.defect...";
$DefectId = 4;
$session->OutputDebugString("\nExported DefectId is ".$DefectId);
则在调用这个hook时,如果已打开dbwin32,则在其窗口会显示:
实例:定义一个使用多种Hooks的缺陷跟踪处理流程模板
在这个例子中,我们创建一个简单的缺陷跟踪处理模板,定义了包括字段缺省Hook,字段值改变Hook,操作权限控制Hook,操作提交Hook,记录类型hook,全局Hook,以及BASE类型操作的通知Hook。这个缺陷跟踪处理系统其实并不完整,但我们的目的就是让大家尽快的对不同类型的Hook及其使用和编写有一个全面、基本的认识。在本例中,我们均使用Perl来编写hooks。
我们在ClearQuest Designer中创建一个基于Blank的模板,创建"defect"记录类型,并为其定义如下的字段:
1) DefectId:整型
2) Description:短字符串
3) OsType:短字符串
4) OsVersion:短字符串
5) StepToRecreate:多行字符串。
"defect"记录类型的字段定义窗口如下图所示:
其中,DefectId和OsVersion均是只读字段。整型DefectId由系统自动累加生成。OsType的值是固定的几个常量之一;OsVersion值则由OsType设定的值来确定。
然后,为其定义如下的状态转换图:
在ClearQuest Designer中,状态转换定义如下图所示:
其中,Dup是DUPLICATE类型,Open是SUBMIT类型。另外还定义Delete类型的"Delete" 操作。只有用户组defectcoordinators的用户才有Delete一个defect的权限。
当验证通过(即Accept)一个fixed defect时,此defect的所有duplicate的defect,包括它的duplicate的duplicate等等,也同时验证通过。同时,在本系统中禁止直接验证某一个duplicate defect。
每当一个操作发生并提交,系统都会在自己的一个log文件中记录相关信息。所以我们还定义了一个Base类型的操作"BaseLog"。
在ClearQuest Designer中,操作定义如下图所示:
为了实现上述功能,我们定义了如下的几个Hook:
1) 字段DefectId的Default Value Hook:
在ClearQuest Designer中打开模板,选择Record Types ->defect ->Fields,双击Fields。点击DefectId字段的Default Value hook,选择SCRIPTS -> Perl:
编写如下的脚本:
sub defectid_DefaultValue{
my($entityDef, $session, $querydef, $queryfields, $queryfield, $resultset,
$fetchStatus, $DefectId);
# 创建一个用于查询Defect记录的查询对象,直接定义其使用的SQL语句:
$entitydef = $entity->GetEntityDefName();
$session = $entity->GetSession();
$querydef = $session->BuildQuery($entitydef);
$querydef->SetSQL("select max(defectid) from defect";
# 运行这个查询,得到当前数据库中DefectId的最大值:
$resultset = $session->BuildResultSet($querydef);
$resultset->Execute();
$fetchStatus = $resultset->MoveNext();
if ($fetchStatus eq $CQPerlExt::CQ_SUCCESS) {
$DefectId = $resultset->GetColumnValue(1);
if ($DefectId > 0){
$DefectId++;
}else{
$DefectId = 1;
}
$entity->SetFieldValue($fieldname,"$DefectId";
}else {
$session->OutputDebugString("\nThis should not happen. fetchStatus is ".$fetchStatus);
}
}
2) OsType的Choice List Hook:
点击DefectId字段的Choice List hook,选择CONSTANT_LIST,并输入"windows","unix","linux"选项,如图所示:
3) OsType的值改变Hook:
同样的,点击DefectId字段的Value Changed hook,选择SCRIPTS -> Perl。编写如下的脚本:
sub ostype_ValueChanged{
my($OsType, $session);
$OsType = $entity->GetFieldValue($fieldname)->GetValue();
$session = $entity->GetSession();
if ($OsType eq "windows"{
$entity->SetFieldValue("OsVersion","Win2k Sp4";
}elsif ($OsType eq "linux"{
$entity->SetFieldValue("OsVersion", "Redhat AS4";
}elseif ($OsType eq "unix"){
$entity->SetFieldValue("OsVersion", "AIX 5L");
}else{
$entity->SetFieldValue("OsVersion", "unknown");
}
}
4) Accept操作的AccessControl Hook:
在本系统中,对于Duplicate的defects不能直接操作。所以编写AccessControl Hook,判断当前的状态是否为Duplicate,如果是,则拒绝执行。
在ClearQuest Designer中打开模板,选择Record Types ->defect ->States and Actions ->Actions,双击Actions。点击Accept操作的Access Control hook,选择SCRIPTS -> Perl:
现在可以开始编写Accept操作的Access Control hook了:
编写如下的脚本:
sub defect_AccessControl {
# Set $result to 1 if the user has permission to perform
# this action, otherwise set it to 0.
my($session, $state);
$session = $entity->GetSession();
$state = $entity->GetFieldValue("State")->GetValue();
if($state eq "duplicate"){
$result = 0;
}else{
$result = 1;
}
return $result;
}
5) Accept操作的Commit Hook:
同样的,点击Accept操作的Commit hook,选择SCRIPTS -> Perl,编写如下的脚本:
sub defect_Commit {
# This hook is fired during the "commit" step of an entity update, so
# it is the appropriate place to put activity which should be bundled
# into the same transaction as the commit, such as subactions or an
# update of external data storage.
my($duplicates, $count, $session, $link, $dup, $validresult);
$session = $entity->GetSession();
$duplicates = $entity->GetDuplicates();
if(!$duplicates){
die;
}
$count = $duplicates->Count();
for($i=0; $i<$count; $i++){
$link = $duplicates->Item($i);
$dup = $link->GetChildEntity();
$dup->EditEntity("Accept");
$validresult = $dup->Validate();
$session->OutputDebugString("\nAccept Validation Error: ".$validresult);
# 调用其duplicate defect的Commit方法,又会触发调用其duplicate defect的Commit Hook,
从而递归验证关闭所有相关联的defects。
$dup->Commit();
}
}
6) 全局 Hook
我们编写一个全局Hook,定义一个简单的方法"BuildLogEntry"来组装一个字串:
在模板中,右击Global Scripts -> Perl,选择Add添加global script,并编写如下脚本:
sub BuildLogEntry {
my($action, $login) = @_;
return "\n*** Action committed ***"."\nAction Taken: ".$action."\nUser: ".$login;
}