kcli-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesekcli Testing and Code Quality
kcli 测试与代码质量
Development Setup
开发环境搭建
bash
undefinedbash
undefinedCreate 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]"
undefinedpip install -e ".[all]"
undefinedLinting
代码检查
pycodestyle (PEP8)
pycodestyle(PEP8规范)
bash
undefinedbash
undefinedLint 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 characterspycodestyle --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
undefinedbash
undefinedCheck 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
undefinedbash
undefinedRun 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服务
- 已配置默认存储池
- 目录下存在SSH密钥对
~/.kcli/
bash
undefinedSetup 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
undefinedsudo 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
undefinedpytest Commands
pytest 命令
bash
undefinedbash
undefinedRun 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
undefinedpython -m pytest tests/test_kvirt.py -v -s
undefinedIntegration Test Script
集成测试脚本
bash
undefinedbash
undefinedFull integration test (used in CI)
Full integration test (used in CI)
.github/testing.sh
undefined.github/testing.sh
undefinedTest Structure
测试结构
Tests are in :
tests/test_kvirt.pypython
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.pypython
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 for integration testing:
.github/test_plan.ymlyaml
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_planCI使用进行集成测试:
.github/test_plan.ymlyaml
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_planValidating Changes
变更验证
Before Committing
提交前检查
bash
undefinedbash
undefined1. 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>
undefinedkcli <your-command>
undefinedManual Testing Patterns
手动测试模式
Testing Provider Changes:
bash
undefined测试提供商变更:
bash
undefinedTest 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:**
```bashkcli -d list vm
kcli -d create vm -i cirros testvm
kcli -d delete vm --yes testvm
**测试计划变更:**
```bashCreate 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
undefinedcat > /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
undefinedCI/CD Pipeline
CI/CD 流水线
The GitHub Actions workflow () runs:
.github/workflows/ci.yml- Lint - pycodestyle + codespell
- Test - Integration tests with libvirt
- Release (main branch only):
- RPM via Copr
- DEB via Cloudsmith
- PyPI package
- Container image to Quay.io
GitHub Actions工作流()会执行以下步骤:
.github/workflows/ci.yml- 代码检查 - pycodestyle + codespell
- 测试 - 基于libvirt的集成测试
- 发布(仅主分支):
- 通过Copr构建RPM包
- 通过Cloudsmith构建DEB包
- 发布PyPI包
- 推送容器镜像至Quay.io
Flake8 Configuration
Flake8 配置
Project uses :
.flake8ini
[flake8]
max-line-length = 120
ignore = E722,E402,E741,W504,E721,E501Note: Flake8 config also ignores (line too long) which is stricter than the CI linting script. The CI script uses pycodestyle directly without E501 ignore.
E501项目使用文件:
.flake8ini
[flake8]
max-line-length = 120
ignore = E722,E402,E741,W504,E721,E501注意: Flake8配置还忽略了(行过长),这比CI代码检查脚本的规则更严格。CI脚本直接使用pycodestyle,未忽略E501。
E501Writing New Tests
编写新测试
When adding tests:
- Use the class pattern
TestK - Return or
{'result': 'success'}{'result': 'failure', 'reason': ...} - Clean up resources in
teardown_class - 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")添加测试时需遵循:
- 使用类的模式
TestK - 返回或
{'result': 'success'}格式的结果{'result': 'failure', 'reason': ...} - 在中清理资源
teardown_class - 使用唯一名称避免冲突
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")