技术开发 频道

ClearQuest的Hook机制

如何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;

    }

 

0
相关文章