kcli-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

kcli Testing and Code Quality

kcli 测试与代码质量

Development Setup

开发环境搭建

bash
undefined
bash
undefined

Create virtual environment

Create virtual environment

python3 -m venv venv . venv/bin/activate
python3 -m venv venv . venv/bin/activate

Install in development mode

Install in development mode

pip install -e .
pip install -e .

Install with all provider dependencies

Install with all provider dependencies

pip install -e ".[all]"
undefined
pip install -e ".[all]"
undefined

Linting

代码检查

pycodestyle (PEP8)

pycodestyle(PEP8规范)

bash
undefined
bash
undefined

Lint all Python files

Lint all Python files

pycodestyle --ignore=E402,W504,E721,E722,E741 --max-line-length=120 kvirt/
pycodestyle --ignore=E402,W504,E721,E722,E741 --max-line-length=120 kvirt/

Lint specific file

Lint specific file

pycodestyle --ignore=E402,W504,E721,E722,E741 --max-line-length=120 kvirt/config.py

**Ignored codes:**
- `E402`: Module level import not at top of file
- `W504`: Line break after binary operator
- `E721`: Do not compare types, use isinstance()
- `E722`: Do not use bare except
- `E741`: Ambiguous variable name

**Max line length:** 120 characters
pycodestyle --ignore=E402,W504,E721,E722,E741 --max-line-length=120 kvirt/config.py

**忽略的规则码:**
- `E402`: 模块级导入未放在文件顶部
- `W504`: 二元运算符后换行
- `E721`: 不要直接比较类型,请使用isinstance()
- `E722`: 不要使用无捕获的except语句
- `E741`: 模糊的变量名

**最大行长度:** 120字符

codespell (Spelling)

codespell(拼写检查)

bash
undefined
bash
undefined

Check spelling

Check spelling

codespell kvirt/ -L "aks"
codespell kvirt/ -L "aks"

The -L flag ignores specific words (aks is Azure Kubernetes Service)

The -L flag ignores specific words (aks is Azure Kubernetes Service)

undefined

**说明:** `-L` 参数用于忽略特定单词(aks指Azure Kubernetes Service)

Combined Linting (CI Script)

组合代码检查(CI脚本)

bash
undefined
bash
undefined

Run the same linting as CI

Run the same linting as CI

.github/linting.sh

**Note:** The linting script excludes `kvirt/bottle.py` (vendored web framework) from checks.
.github/linting.sh

**注意:** 代码检查脚本会排除`kvirt/bottle.py`(引入的第三方Web框架)不进行检查。

Running Tests

运行测试

Prerequisites

前提条件

Tests require:
  • libvirt running locally
  • Default storage pool configured
  • SSH keypair in
    ~/.kcli/
bash
undefined
测试需要满足:
  • 本地运行libvirt服务
  • 已配置默认存储池
  • ~/.kcli/
    目录下存在SSH密钥对
bash
undefined

Setup for testing

Setup for testing

sudo mkdir -p /var/lib/libvirt/images sudo setfacl -m u:$(id -un):rwx /var/lib/libvirt/images mkdir -p ~/.kcli ssh-keygen -t rsa -N '' -f ~/.kcli/id_rsa kcli create pool -p /var/lib/libvirt/images default
undefined
sudo mkdir -p /var/lib/libvirt/images sudo setfacl -m u:$(id -un):rwx /var/lib/libvirt/images mkdir -p ~/.kcli ssh-keygen -t rsa -N '' -f ~/.kcli/id_rsa kcli create pool -p /var/lib/libvirt/images default
undefined

pytest Commands

pytest 命令

bash
undefined
bash
undefined

Run all tests

Run all tests

python -m pytest tests/test_kvirt.py -v
python -m pytest tests/test_kvirt.py -v

Run specific test class

Run specific test class

python -m pytest tests/test_kvirt.py::TestK -v
python -m pytest tests/test_kvirt.py::TestK -v

Run specific test method

Run specific test method

python -m pytest tests/test_kvirt.py::TestK::test_create_vm -v
python -m pytest tests/test_kvirt.py::TestK::test_create_vm -v

Run with output capture disabled

Run with output capture disabled

python -m pytest tests/test_kvirt.py -v -s
undefined
python -m pytest tests/test_kvirt.py -v -s
undefined

Integration Test Script

集成测试脚本

bash
undefined
bash
undefined

Full integration test (used in CI)

Full integration test (used in CI)

.github/testing.sh
undefined
.github/testing.sh
undefined

Test Structure

测试结构

Tests are in
tests/test_kvirt.py
:
python
class TestK:
    @classmethod
    def setup_class(self):
        # Initialize Kconfig and provider
        self.config = Kconfig()
        self.k = self.config.k
        
    def test_list(self):
        result = self.k.list()
        assert result is not None
        
    def test_create_vm(self):
        result = self.config.create_vm(...)
        assert result["result"] == "success"
        
    @classmethod
    def teardown_class(self):
        # Cleanup resources
        self.k.delete_network(...)
        self.k.delete_pool(...)
测试文件位于
tests/test_kvirt.py
python
class TestK:
    @classmethod
    def setup_class(self):
        # Initialize Kconfig and provider
        self.config = Kconfig()
        self.k = self.config.k
        
    def test_list(self):
        result = self.k.list()
        assert result is not None
        
    def test_create_vm(self):
        result = self.config.create_vm(...)
        assert result["result"] == "success"
        
    @classmethod
    def teardown_class(self):
        # Cleanup resources
        self.k.delete_network(...)
        self.k.delete_pool(...)

Test Plan Example

测试计划示例

The CI uses
.github/test_plan.yml
for integration testing:
yaml
parameters:
  pool: default
  image: cirros
  network: mynetwork
  profile: myprofile

{{ image }}:
  type: image
  pool: {{ pool }}

{{ network }}:
  type: network
  cidr: 192.168.125.0/24
  dhcp: true

{{ profile }}:
  type: profile
  image: {{ image }}
  memory: 2048
  numcpus: 2

myvm:
  profile: {{ profile }}
  pool: {{ pool }}
Run it:
bash
kcli create plan -f .github/test_plan.yml test_plan
kcli list plan | grep test_plan
kcli delete plan --yes test_plan
CI使用
.github/test_plan.yml
进行集成测试:
yaml
parameters:
  pool: default
  image: cirros
  network: mynetwork
  profile: myprofile

{{ image }}:
  type: image
  pool: {{ pool }}

{{ network }}:
  type: network
  cidr: 192.168.125.0/24
  dhcp: true

{{ profile }}:
  type: profile
  image: {{ image }}
  memory: 2048
  numcpus: 2

myvm:
  profile: {{ profile }}
  pool: {{ pool }}
运行方式:
bash
kcli create plan -f .github/test_plan.yml test_plan
kcli list plan | grep test_plan
kcli delete plan --yes test_plan

Validating Changes

变更验证

Before Committing

提交前检查

bash
undefined
bash
undefined

1. Run linting

1. Run linting

pycodestyle --ignore=E402,W504,E721,E722,E741 --max-line-length=120 kvirt/
pycodestyle --ignore=E402,W504,E721,E722,E741 --max-line-length=120 kvirt/

2. Check spelling

2. Check spelling

codespell kvirt/ -L "aks"
codespell kvirt/ -L "aks"

3. Run tests (if libvirt available)

3. Run tests (if libvirt available)

python -m pytest tests/test_kvirt.py -v
python -m pytest tests/test_kvirt.py -v

4. Test your specific change manually

4. Test your specific change manually

kcli <your-command>
undefined
kcli <your-command>
undefined

Manual Testing Patterns

手动测试模式

Testing Provider Changes:
bash
undefined
测试提供商变更:
bash
undefined

Test with debug output

Test with debug output

kcli -d list vm kcli -d create vm -i cirros testvm kcli -d delete vm --yes testvm

**Testing Plan Changes:**
```bash
kcli -d list vm kcli -d create vm -i cirros testvm kcli -d delete vm --yes testvm

**测试计划变更:**
```bash

Create minimal test plan

Create minimal test plan

cat > /tmp/test.yml << 'EOF' testvm: image: cirros memory: 512 EOF
kcli create plan -f /tmp/test.yml mytest kcli info plan mytest kcli delete plan --yes mytest
undefined
cat > /tmp/test.yml << 'EOF' testvm: image: cirros memory: 512 EOF
kcli create plan -f /tmp/test.yml mytest kcli info plan mytest kcli delete plan --yes mytest
undefined

CI/CD Pipeline

CI/CD 流水线

The GitHub Actions workflow (
.github/workflows/ci.yml
) runs:
  1. Lint - pycodestyle + codespell
  2. Test - Integration tests with libvirt
  3. Release (main branch only):
    • RPM via Copr
    • DEB via Cloudsmith
    • PyPI package
    • Container image to Quay.io
GitHub Actions工作流(
.github/workflows/ci.yml
)会执行以下步骤:
  1. 代码检查 - pycodestyle + codespell
  2. 测试 - 基于libvirt的集成测试
  3. 发布(仅主分支):
    • 通过Copr构建RPM包
    • 通过Cloudsmith构建DEB包
    • 发布PyPI包
    • 推送容器镜像至Quay.io

Flake8 Configuration

Flake8 配置

Project uses
.flake8
:
ini
[flake8]
max-line-length = 120
ignore = E722,E402,E741,W504,E721,E501
Note: Flake8 config also ignores
E501
(line too long) which is stricter than the CI linting script. The CI script uses pycodestyle directly without E501 ignore.
项目使用
.flake8
文件:
ini
[flake8]
max-line-length = 120
ignore = E722,E402,E741,W504,E721,E501
注意: Flake8配置还忽略了
E501
(行过长),这比CI代码检查脚本的规则更严格。CI脚本直接使用pycodestyle,未忽略E501。

Writing New Tests

编写新测试

When adding tests:
  1. Use the
    TestK
    class pattern
  2. Return
    {'result': 'success'}
    or
    {'result': 'failure', 'reason': ...}
  3. Clean up resources in
    teardown_class
  4. Use unique names to avoid conflicts
python
def test_new_feature(self):
    # Setup
    result = self.k.create_something(name="test-unique-name")
    
    # Assert
    assert result["result"] == "success"
    
    # Cleanup (or use teardown_class)
    self.k.delete_something("test-unique-name")
添加测试时需遵循:
  1. 使用
    TestK
    类的模式
  2. 返回
    {'result': 'success'}
    {'result': 'failure', 'reason': ...}
    格式的结果
  3. teardown_class
    中清理资源
  4. 使用唯一名称避免冲突
python
def test_new_feature(self):
    # Setup
    result = self.k.create_something(name="test-unique-name")
    
    # Assert
    assert result["result"] == "success"
    
    # Cleanup (or use teardown_class)
    self.k.delete_something("test-unique-name")