Files
wehub-resource-sync 91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:19 +08:00

231 lines
7.2 KiB
Python

"""Tests for auth.store module."""
import sqlite3
import threading
from unittest.mock import patch
import pytest
from cua_cli.auth.store import (
CredentialStore,
clear_credentials,
get_api_key,
require_api_key,
save_api_key,
)
class TestCredentialStore:
"""Tests for CredentialStore class."""
def test_init_creates_database(self, tmp_path):
"""Test that initializing creates the database file."""
db_path = tmp_path / "test.db"
CredentialStore(db_path)
assert db_path.exists()
def test_init_creates_parent_directory(self, tmp_path):
"""Test that initializing creates parent directories."""
db_path = tmp_path / "nested" / "dir" / "test.db"
CredentialStore(db_path)
assert db_path.parent.exists()
assert db_path.exists()
def test_set_and_get(self, tmp_path):
"""Test setting and getting a value."""
store = CredentialStore(tmp_path / "test.db")
store.set("test_key", "test_value")
result = store.get("test_key")
assert result == "test_value"
def test_get_nonexistent_key(self, tmp_path):
"""Test getting a nonexistent key returns None."""
store = CredentialStore(tmp_path / "test.db")
result = store.get("nonexistent")
assert result is None
def test_set_overwrites_existing(self, tmp_path):
"""Test that setting an existing key overwrites the value."""
store = CredentialStore(tmp_path / "test.db")
store.set("key", "value1")
store.set("key", "value2")
result = store.get("key")
assert result == "value2"
def test_delete_existing_key(self, tmp_path):
"""Test deleting an existing key returns True."""
store = CredentialStore(tmp_path / "test.db")
store.set("key", "value")
result = store.delete("key")
assert result is True
assert store.get("key") is None
def test_delete_nonexistent_key(self, tmp_path):
"""Test deleting a nonexistent key returns False."""
store = CredentialStore(tmp_path / "test.db")
result = store.delete("nonexistent")
assert result is False
def test_clear_removes_all(self, tmp_path):
"""Test that clear removes all values."""
store = CredentialStore(tmp_path / "test.db")
store.set("key1", "value1")
store.set("key2", "value2")
store.clear()
assert store.get("key1") is None
assert store.get("key2") is None
def test_wal_mode_enabled(self, tmp_path):
"""Test that WAL mode is enabled for concurrent access."""
db_path = tmp_path / "test.db"
CredentialStore(db_path)
conn = sqlite3.connect(db_path)
try:
cursor = conn.execute("PRAGMA journal_mode")
mode = cursor.fetchone()[0]
assert mode.lower() == "wal"
finally:
conn.close()
def test_concurrent_access(self, tmp_path):
"""Test that concurrent access works with WAL mode."""
db_path = tmp_path / "test.db"
store = CredentialStore(db_path)
results = []
errors = []
def writer():
try:
for i in range(10):
store.set(f"key_{i}", f"value_{i}")
except Exception as e:
errors.append(e)
def reader():
try:
for i in range(10):
result = store.get(f"key_{i}")
if result is not None:
results.append(result)
except Exception as e:
errors.append(e)
threads = [
threading.Thread(target=writer),
threading.Thread(target=reader),
threading.Thread(target=reader),
]
for t in threads:
t.start()
for t in threads:
t.join()
assert len(errors) == 0
class TestGetApiKey:
"""Tests for get_api_key function."""
def test_returns_env_var_first(self, monkeypatch, tmp_path):
"""Test that environment variable takes precedence."""
# Set up a store with a different value
with patch("cua_cli.auth.store.CREDENTIALS_DB", tmp_path / "test.db"):
with patch("cua_cli.auth.store._store", None):
monkeypatch.setenv("CUA_API_KEY", "env-key")
save_api_key("stored-key")
result = get_api_key()
assert result == "env-key"
def test_falls_back_to_stored(self, monkeypatch, tmp_path):
"""Test that stored key is used when env var not set."""
with patch("cua_cli.auth.store.CREDENTIALS_DB", tmp_path / "test.db"):
with patch("cua_cli.auth.store._store", None):
monkeypatch.delenv("CUA_API_KEY", raising=False)
save_api_key("stored-key")
result = get_api_key()
assert result == "stored-key"
def test_returns_none_when_not_found(self, monkeypatch, tmp_path):
"""Test that None is returned when no key is found."""
with patch("cua_cli.auth.store.CREDENTIALS_DB", tmp_path / "test.db"):
with patch("cua_cli.auth.store._store", None):
monkeypatch.delenv("CUA_API_KEY", raising=False)
result = get_api_key()
assert result is None
class TestSaveApiKey:
"""Tests for save_api_key function."""
def test_saves_api_key(self, tmp_path, monkeypatch):
"""Test that API key is saved correctly."""
with patch("cua_cli.auth.store.CREDENTIALS_DB", tmp_path / "test.db"):
with patch("cua_cli.auth.store._store", None):
monkeypatch.delenv("CUA_API_KEY", raising=False)
save_api_key("my-api-key")
result = get_api_key()
assert result == "my-api-key"
class TestClearCredentials:
"""Tests for clear_credentials function."""
def test_clears_all_credentials(self, tmp_path, monkeypatch):
"""Test that all credentials are cleared."""
with patch("cua_cli.auth.store.CREDENTIALS_DB", tmp_path / "test.db"):
with patch("cua_cli.auth.store._store", None):
monkeypatch.delenv("CUA_API_KEY", raising=False)
save_api_key("my-api-key")
clear_credentials()
result = get_api_key()
assert result is None
class TestRequireApiKey:
"""Tests for require_api_key function."""
def test_returns_key_when_available(self, monkeypatch):
"""Test that key is returned when available."""
monkeypatch.setenv("CUA_API_KEY", "my-api-key")
result = require_api_key()
assert result == "my-api-key"
def test_raises_when_not_available(self, monkeypatch, tmp_path):
"""Test that RuntimeError is raised when no key available."""
with patch("cua_cli.auth.store.CREDENTIALS_DB", tmp_path / "test.db"):
with patch("cua_cli.auth.store._store", None):
monkeypatch.delenv("CUA_API_KEY", raising=False)
with pytest.raises(RuntimeError) as exc_info:
require_api_key()
assert "No API key configured" in str(exc_info.value)
assert "cua auth login" in str(exc_info.value)