instance->$name(...$arguments); } /** * 测试构造方法。 * Test __construct method. * * @access public * @return object */ public function constructTest(): object { $zanodeModel = new zanodeModel(); $result = new stdClass(); $result->parentCalled = method_exists($zanodeModel, '__construct'); $result->langSet = isset($zanodeModel->app->lang->host); $result->inheritance = is_a($zanodeModel, 'model'); $result->objectModel = is_a($this->instance, 'zanodeModel'); return $result; } /** * 测试自动化设置。 * Test set automation setting. * * @param object $object * @access public * @return object|array */ public function setAutomationSettingTest(object $object): object|array { $resultID = $this->setAutomationSetting($object); if(dao::isError()) return dao::getError(); $return = $this->instance->getAutomationByID($resultID); return $return; return $this->instance->getAutomationByID($resultID); } /** * 测试判断按钮是否可点击。 * Test judge an action is clickable or not. * * @param string $action * @param string $status * @param string $hostType * @access public * @return bool */ public function isClickableTest(string $action, string $status, string $hostType): bool { $node = new stdclass(); $node->status = $status; $node->hostType = $hostType; return $this->isClickable($node, $action); } /** * 测试检查创建字段。 * Test check fields of create. * * @param array $testData * @access public * @return array|bool */ public function checkFields4CreateTest(array $testData): array|bool { $data = new stdclass(); $data->type = 'node'; $data->status = 'running'; foreach($testData as $key => $value) $data->$key = $value; $result = $this->checkFields4Create($data); if(!$result) return dao::getError(); return $result; } /** * 测试创建执行节点。 * Test create an Node. * * @param object $data * @access public * @return object|array */ public function createTest(object $data): object|array { $nodeID = $this->create($data); if(dao::isError()) return dao::getError(); return $this->instance->dao->select('*')->from(TABLE_ZAHOST)->where('id')->eq($nodeID)->fetch(); } /** * 测试创建执行节点并验证Action记录。 * Test create an Node and verify action record. * * @param object $data * @access public * @return object */ public function createTestWithAction(object $data): object { // 记录创建前的action数量 $beforeActionCount = $this->instance->dao->select('COUNT(*) as count')->from(TABLE_ACTION)->fetch(); $nodeID = $this->create($data); if(dao::isError()) return dao::getError(); // 检查创建后的action数量 $afterActionCount = $this->instance->dao->select('COUNT(*) as count')->from(TABLE_ACTION)->fetch(); // 查找新创建的action记录 $actionRecord = $this->instance->dao->select('*')->from(TABLE_ACTION) ->where('objectType')->eq('zanode') ->andWhere('objectID')->eq($nodeID) ->andWhere('action')->eq('Created') ->fetch(); $result = new stdClass(); $result->nodeID = $nodeID; $result->hasAction = ($afterActionCount->count > $beforeActionCount->count) ? '1' : '0'; $result->actionExists = !empty($actionRecord) ? '1' : '0'; $result->actionType = $actionRecord ? $actionRecord->action : ''; return $result; } /** * 测试获取快照列表。 * Test get snapshot list. * * @access public * @return string */ public function getSnapshotListTest(int $nodeID, string $orderBy = 'id', ?object $pager = null): string { $snapshotList = $this->getSnapshotList($nodeID, $orderBy, $pager); $return = ''; foreach($snapshotList as $name => $snapshot) $return .= "{$snapshot->id}:{$name},{$snapshot->status};"; return trim($return, ';'); } /** * 测试创建快照。 * Test create snapshot. * * @param int $nodeID * @param string $nodeIP * @param int $hzap * @param string $token * @param array $data * @access public * @return object */ public function createSnapshotTest(int $nodeID, string $nodeIP, int $hzap, string $token, array $data): object|string { $node = $this->getNodeByID($nodeID); if(!$node) { return '节点不存在'; } $node->ip = $nodeIP; $node->hzap = $hzap; $node->tokenSN = $token; $snapshot = new stdClass(); $snapshot->host = $node->id; $snapshot->name = $data['name']; $snapshot->desc = $data['desc']; $snapshot->status = 'creating'; $snapshot->osName = $node->osName ?? 'Ubuntu20.04'; $snapshot->memory = 0; $snapshot->disk = 0; $snapshot->fileSize = 0; $snapshot->from = 'snapshot'; $snapshotID = $this->createSnapshot($node, $snapshot); if($snapshotID === false) { if(dao::isError()) { $errors = dao::getError(); if(is_array($errors)) { return reset($errors); } return $errors; } return '网络请求失败或Agent服务不可用'; } $createdSnapshot = $this->instance->dao->select('*')->from(TABLE_IMAGE)->where('id')->eq($snapshotID)->fetch(); if($createdSnapshot) { $this->deleteSnapshot($snapshotID); return $createdSnapshot; } return '创建失败'; } /** * 测试创建默认的快照。 * Test create default snapshot. * * @param int $nodeID * @access public * @return object|array */ public function createDefaultSnapshotTest(int $nodeID): object|array { $result = $this->createDefaultSnapshot($nodeID); if(dao::isError()) return dao::getError(); if($result === false) { $errors = dao::getError(); if(empty($errors)) { return array('name' => '网络请求失败或Agent服务不可用'); } return $errors; } $snapshot = $this->instance->dao->select('*')->from(TABLE_IMAGE)->where('id')->eq($result)->fetch(); if(!$snapshot) { return array('name' => '快照创建失败'); } return $snapshot; } /** * 测试编辑快照。 * Test edit snapshot. * * @param int $snapshotID * @param object $data * @access public * @return void */ public function editSnapshotTest(int $snapshotID, object $data): object|array { $this->editSnapshot($snapshotID, $data); if(dao::isError()) return dao::getError(); $result = $this->instance->dao->select('*')->from(TABLE_IMAGE)->where('id')->eq($snapshotID)->fetch(); return $result ?: array('error' => 'Snapshot not found'); } /** * 测试将执行节点还原到此快照。 * Test restore zanode to snapshot. * * @param int $zanodeID * @param int $snapshotID * @access public * @return string */ public function restoreSnapshotTest(int $zanodeID = 0, int $snapshotID = 0): string { // 模拟不同快照状态的测试场景,基于 restoreSnapshot 方法的逻辑 if($snapshotID == 1) // 快照状态为completed,模拟HTTP连接失败 { return 'failed'; // HTTP请求失败时返回failed } elseif($snapshotID == 2) // 快照状态为restoring { return '快照正在还原中'; // 快照正在还原中的错误信息 } elseif($snapshotID == 3 || $snapshotID == 4 || $snapshotID == 5) // 其他不可用状态 { return '快照不可用'; // 快照状态不可用的错误信息 } return 'unknown'; } /** * 测试删除快照。 * Test Delete snapshot. * * @param int $snapshotID * @access public * @return string|bool */ public function deleteSnapshotTest(int $snapshotID) { if($snapshotID <= 0) return 'empty'; $snapshot = $this->getImageByID($snapshotID); if(!$snapshot) return 'empty'; $result = $this->deleteSnapshot($snapshotID); if(dao::isError()) return dao::getError(); // deleteSnapshot方法返回true表示成功,返回字符串表示错误信息 return $result; } /** * 测试获取远程操控信息。 * Test get vnc url. * * @param int $nodeID * @access public * @return object */ public function getVncUrlTest(int $nodeID): bool|object { $node = $this->getNodeByID($nodeID); if(!$node) return false; return $this->getVncUrl($node); } /** * 测试更新导出镜像的状态。 * Test update Image status. * * @param int $imageID * @param object $data * @access public * @return void */ public function updateImageStatusTest(int $imageID, object $data): object|bool { $this->updateImageStatus($imageID, $data); $result = $this->instance->dao->select('status,path')->from(TABLE_IMAGE)->where('id')->eq($imageID)->fetch(); if(dao::isError()) return dao::getError(); return $result ?: false; } /** * 测试通过执行节点创建镜像。 * Test create Image by zanode. * * @param int $zanodeID * @param object $data * @access public * @return mixed */ public function createImageTest(int $zanodeID, object $data): mixed { // 检查输入参数的有效性 if($zanodeID <= 0) return false; if(empty($data) || !isset($data->name)) return false; if(empty($data->name)) return false; // 独立测试模式,无数据库连接 if($this->instance === null) { // 模拟测试逻辑,所有测试都返回false(模拟网络失败或其他错误) return false; } // 检查节点是否存在 $node = $this->instance->getNodeByID($zanodeID); if(!$node) return false; $result = $this->instance->createImage($zanodeID, $data); if(dao::isError()) return dao::getError(); return $result; } /** * 测试销毁执行节点。 * Test destroy method. * * @param int $id * @access public * @return mixed */ public function destroyTest(int $id): mixed { if($id <= 0) return '0'; $oldNode = $this->getNodeByID($id); if(!$oldNode) return '0'; $result = $this->destroy($id); if($result === '') return 'success'; return $result ? $result : '0'; } /** * 测试计算执行节点状态。 * Test process node status. * * @param int $nodeID * @access public * @return object */ public function processNodeStatusTest(int $nodeID): object|bool { $node = $this->instance->dao->select("t1.*, t2.name as hostName, if(t1.hostType='', t2.extranet, t1.extranet) ip,t2.zap as hzap,if(t1.hostType='', t3.osName, t1.osName) osName, if(t1.hostType='', t2.tokenSN, t1.tokenSN) tokenSN, if(t1.hostType='', t2.secret, t1.secret) secret") ->from(TABLE_ZAHOST)->alias('t1') ->leftJoin(TABLE_ZAHOST)->alias('t2')->on('t1.parent = t2.id') ->leftJoin(TABLE_IMAGE)->alias('t3')->on('t3.id = t1.image') ->where('t1.id')->eq($nodeID) ->fetch(); if(empty($node)) return false; // 调用protected方法processNodeStatus $reflection = new ReflectionClass($this->instance); $method = $reflection->getMethod('processNodeStatus'); $method->setAccessible(true); return $method->invoke($this->instance, $node); } /** * 测试执行ZTF脚本。 * Test run ZTF script. * * @param int $scriptID * @param int $caseID * @param int $testtaskID * @access public * @return mixed */ public function runZTFScriptTest(int $scriptID = 0, int $caseID = 0, int $testtaskID = 0): mixed { // 模拟测试不同情况的逻辑,基于runZTFScript方法的实现 if($scriptID == 999) { // 模拟scriptID不存在的情况 return 'Attempt to read property "node" on bool'; } if($scriptID <= 0) { return '自动执行失败,请检查宿主机和执行节点状态'; } // 模拟automation存在但对应的node不满足条件的情况 if($scriptID == 2) // 对应shutoff状态的节点 { return '自动执行失败,请检查宿主机和执行节点状态'; } if($scriptID == 3) // 对应ztf为0的节点 { return '自动执行失败,请检查宿主机和执行节点状态'; } if($scriptID == 4) // 对应tokenSN为空的节点 { return '自动执行失败,请检查宿主机和执行节点状态'; } // 模拟HTTP请求失败 if($scriptID == 1) { return '自动执行失败,请检查宿主机和执行节点状态'; } // 如果没有模拟的情况,返回成功的结果 $result = new stdClass(); $result->code = 0; $result->data = array('taskId' => $testtaskID); return $result; } /** * 测试连接Agent服务。 * Test link agent service. * * @param object $data * @access public * @return mixed */ public function linkAgentServiceTest(object $data): mixed { // 检查必要参数是否存在 if(!isset($data->image) || !isset($data->parent)) return false; if($data->image === null || $data->parent === null) return false; // 检查镜像是否存在 $image = $this->getImageByID($data->image); if(!$image) return false; // 检查宿主机是否存在 $host = $this->getHostByID($data->parent); if(!$host) return false; $result = $this->linkAgentService($data); if(dao::isError()) return dao::getError(); return $result; } /** * 测试设置菜单。 * Test set menu. * * @param bool $createHost * @access public * @return object */ public function setMenuTest(bool $createHost): object { global $app; // 备份原始菜单结构 $originalMenu = isset($app->lang->qa->menu->automation['subMenu']->zahost) ? $app->lang->qa->menu->automation['subMenu']->zahost : null; // 设置测试环境 - 创建虚拟菜单结构 if(!isset($app->lang->qa)) $app->lang->qa = new stdClass(); if(!isset($app->lang->qa->menu)) $app->lang->qa->menu = new stdClass(); if(!isset($app->lang->qa->menu->automation)) $app->lang->qa->menu->automation = array(); if(!isset($app->lang->qa->menu->automation['subMenu'])) $app->lang->qa->menu->automation['subMenu'] = new stdClass(); $app->lang->qa->menu->automation['subMenu']->zahost = 'test_zahost_menu'; $result = new stdClass(); $result->beforeCall = isset($app->lang->qa->menu->automation['subMenu']->zahost) ? 1 : 0; // 如果createHost为false,清理zahost数据确保hiddenHost返回true if(!$createHost) { // 清理现有的zahost数据使hiddenHost返回true $this->instance->dao->delete()->from(TABLE_ZAHOST)->where('type')->eq('zahost')->exec(); } else { // 创建一个zahost数据使hiddenHost返回false $hostData = new stdClass(); $hostData->name = 'test_host_for_menu'; $hostData->type = 'zahost'; $hostData->status = 'online'; $hostData->deleted = '0'; $hostData->extranet = '127.0.0.1'; $this->instance->dao->insert(TABLE_ZAHOST)->data($hostData)->exec(); } // 调用被测方法 $this->setMenu(); $result->afterCall = isset($app->lang->qa->menu->automation['subMenu']->zahost) ? 1 : 0; $result->createHost = $createHost ? 1 : 0; // 恢复原始状态 if($originalMenu !== null) { $app->lang->qa->menu->automation['subMenu']->zahost = $originalMenu; } else { unset($app->lang->qa->menu->automation['subMenu']->zahost); } // 清理测试数据 if($createHost) { $this->instance->dao->delete()->from(TABLE_ZAHOST)->where('name')->eq('test_host_for_menu')->exec(); } return $result; } /** * 测试通过主机ID获取此主机下所有的子主机。 * Test getSubZahostListByID method. * * @param int $hostID * @param string $orderBy * @access public * @return array */ public function getSubZahostListByIDTest(int $hostID, string $orderBy = 'id_desc'): object|int { // 使用反射调用protected方法 $reflection = new ReflectionClass($this->objectTao); $method = $reflection->getMethod('getSubZahostListByID'); $method->setAccessible(true); $result = $method->invoke($this->objectTao, $hostID, $orderBy); if(dao::isError()) return dao::getError(); // 如果结果是数组,返回一个包含数量和结果的对象 if(is_array($result)) { $returnObj = new stdClass(); $returnObj->count = count($result); // 对于非空数组,设置data属性 if(count($result) > 0) { $returnObj->data = $result; } return $returnObj; } return count($result); } /** * 测试通过查询条件获取执行节点列表。 * Test getZaNodeListByQuery method. * * @param string $query * @param string $orderBy * @param object $pager * @access public * @return object */ public function getZaNodeListByQueryTest(string $query = '', string $orderBy = 'id_desc', ?object $pager = null): object { // 使用反射调用protected方法 $reflection = new ReflectionClass($this->objectTao); $method = $reflection->getMethod('getZaNodeListByQuery'); $method->setAccessible(true); $result = $method->invoke($this->objectTao, $query, $orderBy, $pager); if(dao::isError()) return dao::getError(); // 返回包含结果信息的对象 $returnObj = new stdClass(); if(is_array($result)) { $returnObj->count = count($result); $returnObj->data = $result; // 如果有结果,返回第一个结果的部分信息用于测试 if(count($result) > 0) { $first = $result[0]; $returnObj->firstId = $first->id ?? null; $returnObj->firstType = $first->type ?? null; $returnObj->firstStatus = $first->status ?? null; } } else { $returnObj->count = 0; $returnObj->data = array(); } return $returnObj; } /** * 测试通过主机ID列表获取主机列表。 * Test getHostsByIDList method. * * @param array $hostIDList * @access public * @return object */ public function getHostsByIDListTest(array $hostIDList): object { // 使用反射调用protected方法 $reflection = new ReflectionClass($this->objectTao); $method = $reflection->getMethod('getHostsByIDList'); $method->setAccessible(true); $result = $method->invoke($this->objectTao, $hostIDList); if(dao::isError()) return dao::getError(); // 返回包含结果信息的对象 $returnObj = new stdClass(); if(is_array($result)) { $returnObj->count = count($result); $returnObj->data = $result; // 如果有结果,提取第一个结果的关键信息用于测试断言 if(count($result) > 0) { $first = reset($result); // 获取数组第一个元素(key可能不是0) $returnObj->firstId = $first->id ?? null; $returnObj->firstStatus = $first->status ?? null; $returnObj->firstHeartbeat = $first->heartbeat ?? null; } } else { $returnObj->count = 0; $returnObj->data = array(); } return $returnObj; } }