-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/usr/bin/env bash | ||
use flake |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: Test | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: "3.11" | ||
|
||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install "home-assistant==2024.2.0" | ||
pip install pytest-homeassistant-custom-component | ||
pip install .[dev] | ||
- name: Run tests | ||
run: | | ||
pytest tests/ -v --cov=custom_components.cowboy |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[pytest] | ||
testpaths = tests | ||
norecursedirs = .git custom_components | ||
asyncio_mode = auto | ||
|
||
# Add custom_components to Python path | ||
pythonpath = . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"""Test configuration for cowboy integration.""" | ||
import os | ||
import sys | ||
from pathlib import Path | ||
|
||
# Add the root directory to Python path | ||
ROOT_DIR = Path(__file__).parents[1].resolve() | ||
sys.path.insert(0, str(ROOT_DIR)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
"""Tests for cowboy integration.""" | ||
from unittest.mock import patch | ||
import pytest | ||
from homeassistant import config_entries, setup | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD | ||
from homeassistant.helpers import device_registry as dr | ||
from custom_components.cowboy.const import DOMAIN | ||
from custom_components.cowboy._client import CowboyAPIClient | ||
|
||
# This is an example configuration entry | ||
MOCK_CONFIG = { | ||
CONF_USERNAME: "[email protected]", | ||
CONF_PASSWORD: "test_password" | ||
} | ||
|
||
MOCK_BIKE_RESPONSE = { | ||
"data": { | ||
"bike": { | ||
"id": "123", | ||
"nickname": "Test Bike", | ||
"model": {"name": "Test Model"}, | ||
"serial_number": "CB123456", | ||
"firmware_version": "1.0.0" | ||
} | ||
} | ||
} | ||
|
||
@pytest.fixture(autouse=True) | ||
def auto_enable_custom_integrations(enable_custom_integrations): | ||
"""Enable custom integrations for testing.""" | ||
yield | ||
|
||
async def test_setup_unload_and_reload_entry(hass: HomeAssistant): | ||
"""Test setup and unload of an entry.""" | ||
# Mock both the API client and requests to avoid actual API calls | ||
with patch('custom_components.cowboy._client.requests') as mock_requests: | ||
# Configure the mock response | ||
mock_response = mock_requests.post.return_value | ||
mock_response.status_code = 200 | ||
mock_response.json.return_value = MOCK_BIKE_RESPONSE | ||
mock_response.headers = { | ||
"Access-Token": "test-token", | ||
"Uid": "[email protected]", | ||
"Client": "test-client", | ||
"Expiry": "9999999999" | ||
} | ||
|
||
# Test that we can setup the entry | ||
entry = config_entries.ConfigEntry( | ||
version=1, | ||
minor_version=1, | ||
domain=DOMAIN, | ||
title="Test", | ||
data=MOCK_CONFIG, | ||
source="test", | ||
options={}, | ||
unique_id="uniqueid", | ||
discovery_keys=set(), | ||
) | ||
|
||
# Add entry to Home Assistant | ||
hass.config_entries._entries[entry.entry_id] = entry | ||
|
||
assert await hass.config_entries.async_setup(entry.entry_id) | ||
await hass.async_block_till_done() | ||
|
||
# Check that the entry is loaded | ||
assert DOMAIN in hass.data | ||
assert entry.entry_id in hass.data[DOMAIN] | ||
|
||
# Test that we can unload the entry | ||
assert await hass.config_entries.async_unload(entry.entry_id) | ||
await hass.async_block_till_done() | ||
|
||
# Clean up devices | ||
device_registry = dr.async_get(hass) | ||
devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id) | ||
for device in devices: | ||
device_registry.async_remove_device(device.id) | ||
|
||
# Clean up the entry | ||
hass.config_entries._entries.pop(entry.entry_id) | ||
assert not hass.data.get(DOMAIN) | ||
|
||
async def test_setup_entry_fails_on_auth_error(hass: HomeAssistant): | ||
"""Test setup with authentication failure.""" | ||
with patch('custom_components.cowboy._client.requests') as mock_requests: | ||
# Configure the mock to simulate auth failure | ||
mock_requests.post.side_effect = Exception("Auth failed") | ||
|
||
entry = config_entries.ConfigEntry( | ||
version=1, | ||
minor_version=1, | ||
domain=DOMAIN, | ||
title="Test", | ||
data=MOCK_CONFIG, | ||
source="test", | ||
options={}, | ||
unique_id="uniqueid", | ||
discovery_keys=set(), | ||
) | ||
|
||
# Add entry to Home Assistant | ||
hass.config_entries._entries[entry.entry_id] = entry | ||
|
||
# Setup should fail | ||
assert not await hass.config_entries.async_setup(entry.entry_id) | ||
await hass.async_block_till_done() | ||
|
||
# Clean up devices | ||
device_registry = dr.async_get(hass) | ||
devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id) | ||
for device in devices: | ||
device_registry.async_remove_device(device.id) | ||
|
||
# Clean up the entry | ||
hass.config_entries._entries.pop(entry.entry_id) | ||
# Entry should not be loaded | ||
assert DOMAIN not in hass.data | ||
|
||
async def test_config_flow_validation(hass: HomeAssistant): | ||
"""Test the config flow validation.""" | ||
with patch('custom_components.cowboy._client.requests') as mock_requests: | ||
# Configure the mock response | ||
mock_response = mock_requests.post.return_value | ||
mock_response.status_code = 200 | ||
mock_response.json.return_value = MOCK_BIKE_RESPONSE | ||
mock_response.headers = { | ||
"Access-Token": "test-token", | ||
"Uid": "[email protected]", | ||
"Client": "test-client", | ||
"Expiry": "9999999999" | ||
} | ||
|
||
result = await hass.config_entries.flow.async_init( | ||
DOMAIN, context={"source": config_entries.SOURCE_USER} | ||
) | ||
|
||
assert result["type"] == "form" | ||
assert result["step_id"] == "user" | ||
|
||
# Test form submission | ||
result = await hass.config_entries.flow.async_configure( | ||
result["flow_id"], | ||
user_input=MOCK_CONFIG | ||
) | ||
|
||
assert result["type"] == "create_entry" | ||
|
||
# Clean up devices for any created entries | ||
device_registry = dr.async_get(hass) | ||
for entry in hass.config_entries._entries.values(): | ||
if entry.domain == DOMAIN: | ||
devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id) | ||
for device in devices: | ||
device_registry.async_remove_device(device.id) | ||
|
||
# Clean up any config entries that were created | ||
for entry in hass.config_entries._entries.copy(): | ||
await hass.config_entries.async_remove(entry) |