flow
This commit is contained in:
215
tests/test_self_hosting.py
Normal file
215
tests/test_self_hosting.py
Normal file
@@ -0,0 +1,215 @@
|
||||
"""Tests for self-hosting flow config from dotfiles repository."""
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from flow.core import paths as paths_module
|
||||
from flow.core.config import load_config, load_manifest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_paths(tmp_path, monkeypatch):
|
||||
"""Mock path constants for testing."""
|
||||
config_dir = tmp_path / "config"
|
||||
dotfiles_dir = tmp_path / "dotfiles"
|
||||
|
||||
config_dir.mkdir()
|
||||
dotfiles_dir.mkdir()
|
||||
|
||||
test_paths = {
|
||||
"config_dir": config_dir,
|
||||
"dotfiles_dir": dotfiles_dir,
|
||||
"local_config": config_dir / "config",
|
||||
"local_manifest": config_dir / "manifest.yaml",
|
||||
"dotfiles_config": dotfiles_dir / "flow" / ".config" / "flow" / "config",
|
||||
"dotfiles_manifest": dotfiles_dir / "flow" / ".config" / "flow" / "manifest.yaml",
|
||||
}
|
||||
|
||||
# Patch at the paths module level
|
||||
monkeypatch.setattr(paths_module, "CONFIG_FILE", test_paths["local_config"])
|
||||
monkeypatch.setattr(paths_module, "MANIFEST_FILE", test_paths["local_manifest"])
|
||||
monkeypatch.setattr(paths_module, "DOTFILES_CONFIG", test_paths["dotfiles_config"])
|
||||
monkeypatch.setattr(paths_module, "DOTFILES_MANIFEST", test_paths["dotfiles_manifest"])
|
||||
|
||||
return test_paths
|
||||
|
||||
|
||||
def test_load_manifest_priority_dotfiles_first(mock_paths):
|
||||
"""Test that dotfiles manifest takes priority over local."""
|
||||
# Create both manifests
|
||||
local_manifest = mock_paths["local_manifest"]
|
||||
dotfiles_manifest = mock_paths["dotfiles_manifest"]
|
||||
|
||||
local_manifest.write_text("profiles:\n local:\n os: linux")
|
||||
|
||||
dotfiles_manifest.parent.mkdir(parents=True)
|
||||
dotfiles_manifest.write_text("profiles:\n dotfiles:\n os: macos")
|
||||
|
||||
# Should load from dotfiles
|
||||
manifest = load_manifest()
|
||||
assert "dotfiles" in manifest.get("profiles", {})
|
||||
assert "local" not in manifest.get("profiles", {})
|
||||
|
||||
|
||||
def test_load_manifest_fallback_to_local(mock_paths):
|
||||
"""Test fallback to local manifest when dotfiles doesn't exist."""
|
||||
local_manifest = mock_paths["local_manifest"]
|
||||
local_manifest.write_text("profiles:\n local:\n os: linux")
|
||||
|
||||
# Dotfiles manifest doesn't exist
|
||||
manifest = load_manifest()
|
||||
assert "local" in manifest.get("profiles", {})
|
||||
|
||||
|
||||
def test_load_manifest_empty_when_none_exist(mock_paths):
|
||||
"""Test empty dict returned when no manifests exist."""
|
||||
manifest = load_manifest()
|
||||
assert manifest == {}
|
||||
|
||||
|
||||
def test_load_config_priority_dotfiles_first(mock_paths):
|
||||
"""Test that dotfiles config takes priority over local."""
|
||||
local_config = mock_paths["local_config"]
|
||||
dotfiles_config = mock_paths["dotfiles_config"]
|
||||
|
||||
# Create local config
|
||||
local_config.write_text(
|
||||
"[repository]\n"
|
||||
"dotfiles_url = https://github.com/user/dotfiles-local.git\n"
|
||||
)
|
||||
|
||||
# Create dotfiles config
|
||||
dotfiles_config.parent.mkdir(parents=True)
|
||||
dotfiles_config.write_text(
|
||||
"[repository]\n"
|
||||
"dotfiles_url = https://github.com/user/dotfiles-from-repo.git\n"
|
||||
)
|
||||
|
||||
# Should load from dotfiles
|
||||
config = load_config()
|
||||
assert "dotfiles-from-repo" in config.dotfiles_url
|
||||
|
||||
|
||||
def test_load_config_fallback_to_local(mock_paths):
|
||||
"""Test fallback to local config when dotfiles doesn't exist."""
|
||||
local_config = mock_paths["local_config"]
|
||||
local_config.write_text(
|
||||
"[repository]\n"
|
||||
"dotfiles_url = https://github.com/user/dotfiles-local.git\n"
|
||||
)
|
||||
|
||||
# Dotfiles config doesn't exist
|
||||
config = load_config()
|
||||
assert "dotfiles-local" in config.dotfiles_url
|
||||
|
||||
|
||||
def test_load_config_empty_when_none_exist(mock_paths):
|
||||
"""Test default config returned when no configs exist."""
|
||||
config = load_config()
|
||||
assert config.dotfiles_url == ""
|
||||
assert config.dotfiles_branch == "main"
|
||||
|
||||
|
||||
def test_self_hosting_workflow(tmp_path, monkeypatch):
|
||||
"""Test complete self-hosting workflow.
|
||||
|
||||
Simulates:
|
||||
1. User has dotfiles repo with flow config
|
||||
2. Flow links its own config from dotfiles
|
||||
3. Flow reads from self-hosted location
|
||||
"""
|
||||
# Setup paths
|
||||
home = tmp_path / "home"
|
||||
dotfiles = tmp_path / "dotfiles"
|
||||
home.mkdir()
|
||||
dotfiles.mkdir()
|
||||
|
||||
# Create flow package in dotfiles
|
||||
flow_pkg = dotfiles / "flow" / ".config" / "flow"
|
||||
flow_pkg.mkdir(parents=True)
|
||||
|
||||
# Create manifest in dotfiles
|
||||
manifest_content = {
|
||||
"profiles": {
|
||||
"test-env": {
|
||||
"os": "linux",
|
||||
"packages": {"standard": ["git", "vim"]},
|
||||
}
|
||||
}
|
||||
}
|
||||
(flow_pkg / "manifest.yaml").write_text(yaml.dump(manifest_content))
|
||||
|
||||
# Create config in dotfiles
|
||||
(flow_pkg / "config").write_text(
|
||||
"[repository]\n"
|
||||
"dotfiles_url = https://github.com/user/dotfiles.git\n"
|
||||
)
|
||||
|
||||
# Mock paths to use our temp directories
|
||||
monkeypatch.setattr(paths_module, "DOTFILES_MANIFEST", flow_pkg / "manifest.yaml")
|
||||
monkeypatch.setattr(paths_module, "DOTFILES_CONFIG", flow_pkg / "config")
|
||||
monkeypatch.setattr(paths_module, "MANIFEST_FILE", home / ".config" / "devflow" / "manifest.yaml")
|
||||
monkeypatch.setattr(paths_module, "CONFIG_FILE", home / ".config" / "devflow" / "config")
|
||||
|
||||
# Load config and manifest - should come from dotfiles
|
||||
manifest = load_manifest()
|
||||
config = load_config()
|
||||
|
||||
assert "test-env" in manifest.get("profiles", {})
|
||||
assert "github.com/user/dotfiles.git" in config.dotfiles_url
|
||||
|
||||
|
||||
def test_manifest_cascade_with_symlink(tmp_path, monkeypatch):
|
||||
"""Test that loading works correctly when symlink is used."""
|
||||
# Setup
|
||||
dotfiles = tmp_path / "dotfiles"
|
||||
home_config = tmp_path / "home" / ".config" / "flow"
|
||||
flow_pkg = dotfiles / "flow" / ".config" / "flow"
|
||||
|
||||
flow_pkg.mkdir(parents=True)
|
||||
home_config.mkdir(parents=True)
|
||||
|
||||
# Create manifest in dotfiles
|
||||
manifest_content = {"profiles": {"from-dotfiles": {"os": "linux"}}}
|
||||
(flow_pkg / "manifest.yaml").write_text(yaml.dump(manifest_content))
|
||||
|
||||
# Create symlink from home config to dotfiles
|
||||
manifest_link = home_config / "manifest.yaml"
|
||||
manifest_link.symlink_to(flow_pkg / "manifest.yaml")
|
||||
|
||||
# Mock paths
|
||||
monkeypatch.setattr(paths_module, "DOTFILES_MANIFEST", flow_pkg / "manifest.yaml")
|
||||
monkeypatch.setattr(paths_module, "MANIFEST_FILE", manifest_link)
|
||||
|
||||
# Load - should work through symlink
|
||||
manifest = load_manifest()
|
||||
assert "from-dotfiles" in manifest.get("profiles", {})
|
||||
|
||||
|
||||
def test_config_priority_documentation(mock_paths):
|
||||
"""Document the config loading priority for users."""
|
||||
# This test serves as documentation of the cascade behavior
|
||||
|
||||
# Priority 1: Dotfiles repo (self-hosted)
|
||||
dotfiles_manifest = mock_paths["dotfiles_manifest"]
|
||||
dotfiles_manifest.parent.mkdir(parents=True)
|
||||
dotfiles_manifest.write_text("profiles:\n priority-1: {}")
|
||||
|
||||
manifest = load_manifest()
|
||||
assert "priority-1" in manifest.get("profiles", {})
|
||||
|
||||
# If we remove dotfiles, falls back to Priority 2: Local override
|
||||
dotfiles_manifest.unlink()
|
||||
local_manifest = mock_paths["local_manifest"]
|
||||
local_manifest.write_text("profiles:\n priority-2: {}")
|
||||
|
||||
manifest = load_manifest()
|
||||
assert "priority-2" in manifest.get("profiles", {})
|
||||
|
||||
# If neither exists, Priority 3: Empty fallback
|
||||
local_manifest.unlink()
|
||||
manifest = load_manifest()
|
||||
assert manifest == {}
|
||||
Reference in New Issue
Block a user