#!/usr/bin/env python3
# coding: utf-8
# Copyright 2024 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===========================================================================
"""
install_sys_pkg.py 系统测试
测试 ascend_deployer/library/install_sys_pkg.py 模块。
"""

import abc
import os
import sys
import types
from unittest.mock import patch, MagicMock, Mock

# 添加项目根目录到路径,以便导入 library_test
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))
test_dir = os.path.join(project_root, 'test')

# 使用动态方式添加路径
path_method = getattr(sys, 'path')
insert_method = getattr(path_method, 'insert')

# 确保路径唯一性,避免重复添加
if project_root not in path_method:
    insert_method(0, project_root)
if test_dir not in path_method:
    insert_method(0, test_dir)

from library_test.base_test import BaseLibraryTest
from library_test.mock_manage.mock_model.mock_ansible_module import AnsibleModule
from library_test.mock_manage.mock_handlers.mock_cmd_handler import MockCmdHandler


ANSIBLE_FIELD = "ansible"
MODULE_UTILS_FIELD = f"{ANSIBLE_FIELD}.module_utils"
BASIC_FIELD = f"{MODULE_UTILS_FIELD}.basic"
COMMON_INFO_FIELD = f"{MODULE_UTILS_FIELD}.common_info"
PATH_MANAGER_FIELD = f"{MODULE_UTILS_FIELD}.path_manager"
SAFE_FILE_HANDLER_FIELD = f"{MODULE_UTILS_FIELD}.safe_file_handler"
COMMON_UTILS_FIELD = f"{MODULE_UTILS_FIELD}.common_utils"

DOCKER_FIELD = "docker"
DOCKER_CE_FIELD = "docker-ce"

OS_FIELD = "CentOS_7.6_aarch64"



class TestBaseSysPkg(BaseLibraryTest, metaclass=abc.ABCMeta):
    TESTCASE_DIR = os.path.join(os.path.dirname(__file__), "testcase")

    @classmethod
    def get_module_path(cls):
        return "ascend_deployer.library.install_sys_pkg"

    @classmethod
    def get_testcase_path(cls):
        return os.path.join(cls.TESTCASE_DIR, "sys_pkg.yml")

    @classmethod
    def setUpClass(cls):
        # 先调用父类的setUp
        super().setUpClass()
        
        # 确保 ansible 模块结构被正确模拟
        if ANSIBLE_FIELD in sys.modules:
            del sys.modules[ANSIBLE_FIELD]
        if f'{MODULE_UTILS_FIELD}' in sys.modules:
            del sys.modules[f'{MODULE_UTILS_FIELD}']
        if BASIC_FIELD in sys.modules:
            del sys.modules[BASIC_FIELD]
        if COMMON_INFO_FIELD in sys.modules:
            del sys.modules[COMMON_INFO_FIELD]
        if COMMON_UTILS_FIELD in sys.modules:
            del sys.modules[COMMON_UTILS_FIELD]
        if PATH_MANAGER_FIELD in sys.modules:
            del sys.modules[PATH_MANAGER_FIELD]
        if SAFE_FILE_HANDLER_FIELD in sys.modules:
            del sys.modules[SAFE_FILE_HANDLER_FIELD]
        
        # 模拟 ansible 模块结构
        sys.modules[ANSIBLE_FIELD] = types.ModuleType(ANSIBLE_FIELD)
        sys.modules[f'{MODULE_UTILS_FIELD}'] = types.ModuleType(MODULE_UTILS_FIELD)
        sys.modules[BASIC_FIELD] = types.ModuleType(BASIC_FIELD)
        sys.modules[COMMON_INFO_FIELD] = types.ModuleType(COMMON_INFO_FIELD)
        sys.modules[COMMON_UTILS_FIELD] = types.ModuleType(COMMON_UTILS_FIELD)
        sys.modules[PATH_MANAGER_FIELD] = types.ModuleType(PATH_MANAGER_FIELD)
        sys.modules[SAFE_FILE_HANDLER_FIELD] = types.ModuleType(SAFE_FILE_HANDLER_FIELD)

        # 创建模拟的 AnsibleModule 类
        def mock_ansible_module(argument_spec=None, **kwargs):
            mock_module = Mock()
            mock_module.params = {}
            mock_module.fail_json = Mock(side_effect=Exception("Failed"))
            mock_module.exit_json = Mock()
            mock_module.get_bin_path = Mock(return_value=None)
            mock_module.run_command = Mock(return_value=(0, "", ""))
            mock_module.log = Mock()
            return mock_module

        # 将模拟的 AnsibleModule 赋值给模块
        sys.modules[BASIC_FIELD].AnsibleModule = mock_ansible_module
        
        # 模拟其他所需的模块和函数
        sys.modules[COMMON_INFO_FIELD].get_os_and_arch = Mock(return_value=OS_FIELD)
        sys.modules[COMMON_INFO_FIELD].need_skip_sys_package = Mock(return_value=False)
        sys.modules[COMMON_INFO_FIELD].DeployStatus = Mock()
        sys.modules[COMMON_INFO_FIELD].DeployStatus.SKIP = "skip"
        sys.modules[COMMON_INFO_FIELD].OSName = Mock()
        sys.modules[COMMON_INFO_FIELD].OSName.BCLINUX_21_10_AARCH64 = "BCLinux 21.10 aarch64"
        sys.modules[COMMON_INFO_FIELD].OSName.BCLINUX_21_10U4_AARCH64 = "BCLinux 21.10U4 aarch64"
        
        sys.modules[COMMON_UTILS_FIELD].ensure_docker_daemon_exist = Mock()
        
        sys.modules[PATH_MANAGER_FIELD].TmpPath = Mock()
        sys.modules[PATH_MANAGER_FIELD].TmpPath.ROOT = "/tmp"
        
        sys.modules[SAFE_FILE_HANDLER_FIELD].SafeFileHandler = Mock()
        sys.modules[SAFE_FILE_HANDLER_FIELD].SafeFileHandler.safe_read_json = Mock(return_value={
            "rpm_os": [OS_FIELD],
            "codename": {OS_FIELD: "bionic"},
            "common_docker": [DOCKER_FIELD, DOCKER_CE_FIELD],
            "euler_docker": [DOCKER_FIELD, DOCKER_CE_FIELD],
            "debian_docker": [DOCKER_FIELD, DOCKER_CE_FIELD]
        })
        sys.modules[SAFE_FILE_HANDLER_FIELD].SafeFileHandler.safe_read = Mock(return_value="")
        sys.modules[SAFE_FILE_HANDLER_FIELD].SafeFileHandler.safe_write = Mock()
        
        # 在每个测试前创建mock
        cls.get_os_and_arch_mocker = cls._mock_get_os_and_arch()
        cls.need_skip_sys_package_mocker = cls._mock_need_skip_sys_package()
        
        from ascend_deployer.library.install_sys_pkg import SysInstaller
        cls.SysInstaller = SysInstaller
    
    @classmethod
    def _mock_get_os_and_arch(cls):
        """mock get_os_and_arch() 方法"""
        patcher = patch(cls.get_module_path() + ".get_os_and_arch")
        mocker = patcher.start()
        mocker.return_value = OS_FIELD
        return mocker
    
    @classmethod
    def _mock_need_skip_sys_package(cls):
        """mock need_skip_sys_package() 方法"""
        patcher = patch(cls.get_module_path() + ".need_skip_sys_package")
        mocker = patcher.start()
        mocker.return_value = False
        return mocker


class TestSysInstaller(TestBaseSysPkg):
    """测试 SysInstaller 类"""
    
    def test_create_config_file(self):
        """测试创建配置文件"""
        params = {
            "nexus_url": "http://test-nexus.com",
            "resources_dir": "/tmp/test",
            "pkg_type": "rpm",
            "ansible_run_tags": ["sys_pkg"]
        }
        
        module = self._create_ansible_module(params)
        
        # Mock nexus_config
        nexus_config = {
            "rpm_os": [OS_FIELD],
            "codename": {OS_FIELD: "bionic"}
        }
        
        with patch('ascend_deployer.library.install_sys_pkg.SafeFileHandler.safe_read_json') \
            as mock_read_json:
            mock_read_json.return_value = nexus_config
            
            with patch('ascend_deployer.library.install_sys_pkg.SafeFileHandler.safe_write') \
                as mock_write:
                installer = self.SysInstaller(module, "http://test-nexus.com", OS_FIELD, "/tmp/test", "rpm")
                installer.create_config_file()
                
                # 验证 safe_write 被调用
                mock_write.assert_called_once()
                
                # 获取写入的配置内容
                call_args = mock_write.call_args
                file_path = call_args[0][0]
                content = call_args[0][1]
                
                # 验证配置文件路径
                self.assertIn("sources.repo", file_path)
                
                # 验证配置内容
                self.assertIn("[nexus]", content)
                self.assertIn(f"name = {OS_FIELD}", content)
                self.assertIn(f"baseurl = http://test-nexus.com/repository/{OS_FIELD}/", content)
                self.assertIn("gpgcheck = 0", content)
                self.assertIn("enabled = 1", content)
    
    def _create_ansible_module(self, params):
        """创建模拟的 AnsibleModule 实例"""
        cmd_handler = MockCmdHandler([], {})
        return AnsibleModule(params, cmd_handler)


if __name__ == '__main__':
    import unittest
    unittest.main()