Coverage for tests/test_archive.py: 100%
84 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
1from pathlib import Path 1abcdefg
3import fastar 1abcdefg
4import pytest 1abcdefg
6from fastapi_cloud_cli.commands.deploy.archive import archive 1abcdefg
9@pytest.fixture 1abcdefg
10def src_path(tmp_path: Path) -> Path: 1abcdefg
11 path = tmp_path / "source" 1abcdefg
12 path.mkdir() 1abcdefg
13 return path 1abcdefg
16@pytest.fixture 1abcdefg
17def dst_path(tmp_path: Path) -> Path: 1abcdefg
18 path = tmp_path / "destination" 1abcdefg
19 path.mkdir() 1abcdefg
20 return path 1abcdefg
23@pytest.fixture 1abcdefg
24def tar_path(tmp_path: Path) -> Path: 1abcdefg
25 return tmp_path / "archive.tar" 1abcdefg
28def test_archive_creates_tar_file(src_path: Path, tar_path: Path) -> None: 1abcdefg
29 (src_path / "main.py").write_text("print('hello')") 1QRSTUVW
30 (src_path / "config.json").write_text('{"key": "value"}') 1QRSTUVW
31 (src_path / "subdir").mkdir() 1QRSTUVW
32 (src_path / "subdir" / "utils.py").write_text("def helper(): pass") 1QRSTUVW
34 archive(src_path, tar_path) 1QRSTUVW
35 assert tar_path.exists() 1QRSTUVW
38def test_archive_excludes_venv_and_similar_folders( 1abcdefg
39 src_path: Path, tar_path: Path, dst_path: Path
40) -> None:
41 """Should exclude .venv directory from archive."""
42 # the only files we want to include
43 (src_path / "main.py").write_text("print('hello')") 1hijklmn
44 (src_path / "static").mkdir() 1hijklmn
45 (src_path / "static" / "index.html").write_text("<html></html>") 1hijklmn
46 # virtualenv
47 (src_path / ".venv").mkdir() 1hijklmn
48 (src_path / ".venv" / "lib").mkdir() 1hijklmn
49 (src_path / ".venv" / "lib" / "package.py").write_text("# package") 1hijklmn
50 # pycache
51 (src_path / "__pycache__").mkdir() 1hijklmn
52 (src_path / "__pycache__" / "main.cpython-311.pyc").write_text("bytecode") 1hijklmn
53 # pyc files
54 (src_path / "main.pyc").write_text("bytecode") 1hijklmn
55 # mypy/pytest
56 (src_path / ".mypy_cache").mkdir() 1hijklmn
57 (src_path / ".mypy_cache" / "file.json").write_text("{}") 1hijklmn
58 (src_path / ".pytest_cache").mkdir() 1hijklmn
59 (src_path / ".pytest_cache" / "cache.db").write_text("data") 1hijklmn
61 archive(src_path, tar_path) 1hijklmn
63 with fastar.open(tar_path, "r") as tar: 1hijklmn
64 tar.unpack(dst_path) 1hijklmn
66 assert set(dst_path.glob("**/*")) == { 1hijklmn
67 dst_path / "main.py",
68 dst_path / "static",
69 dst_path / "static" / "index.html",
70 }
73def test_archive_preserves_relative_paths( 1abcdefg
74 src_path: Path, tar_path: Path, dst_path: Path
75) -> None:
76 (src_path / "src").mkdir() 1JKLMNOP
77 (src_path / "src" / "app").mkdir() 1JKLMNOP
78 (src_path / "src" / "app" / "main.py").write_text("print('hello')") 1JKLMNOP
80 archive(src_path, tar_path) 1JKLMNOP
82 with fastar.open(tar_path, "r") as tar: 1JKLMNOP
83 tar.unpack(dst_path) 1JKLMNOP
85 assert set(dst_path.glob("**/*")) == { 1JKLMNOP
86 dst_path / "src",
87 dst_path / "src" / "app",
88 dst_path / "src" / "app" / "main.py",
89 }
92def test_archive_respects_fastapicloudignore( 1abcdefg
93 src_path: Path, tar_path: Path, dst_path: Path
94) -> None:
95 """Should exclude files specified in .fastapicloudignore."""
96 (src_path / "main.py").write_text("print('hello')") 1vwxyzAB
97 (src_path / "config.py").write_text("CONFIG = 'value'") 1vwxyzAB
98 (src_path / "secrets.env").write_text("SECRET_KEY=xyz") 1vwxyzAB
99 (src_path / "data").mkdir() 1vwxyzAB
100 (src_path / "data" / "file.txt").write_text("data") 1vwxyzAB
102 (src_path / ".fastapicloudignore").write_text("secrets.env\ndata/\n") 1vwxyzAB
104 archive(src_path, tar_path) 1vwxyzAB
106 with fastar.open(tar_path, "r") as tar: 1vwxyzAB
107 tar.unpack(dst_path) 1vwxyzAB
109 assert set(dst_path.glob("**/*")) == { 1vwxyzAB
110 dst_path / "main.py",
111 dst_path / "config.py",
112 }
115def test_archive_respects_fastapicloudignore_unignore( 1abcdefg
116 src_path: Path, tar_path: Path, dst_path: Path
117) -> None:
118 """Test we can use .fastapicloudignore to unignore files inside .gitignore"""
119 (src_path / "main.py").write_text("print('hello')") 1opqrstu
121 (src_path / "ignore_me.txt").write_text("You should ignore me") 1opqrstu
123 (src_path / "static/build").mkdir(exist_ok=True, parents=True) 1opqrstu
124 (src_path / "static/build/style.css").write_text("body { background: #bada55 }") 1opqrstu
126 # Rignore needs a .git folder to make .gitignore work
127 (src_path / ".git").mkdir(exist_ok=True, parents=True) 1opqrstu
128 (src_path / ".git" / "config").write_text("[core]\n\trepositoryformatversion = 0") 1opqrstu
129 (src_path / ".gitignore").write_text("ignore_me.txt\nbuild/") 1opqrstu
131 (src_path / ".fastapicloudignore").write_text("!static/build") 1opqrstu
133 archive(src_path, tar_path) 1opqrstu
135 with fastar.open(tar_path, "r") as tar: 1opqrstu
136 tar.unpack(dst_path) 1opqrstu
138 assert set(dst_path.glob("**/*")) == { 1opqrstu
139 dst_path / "main.py",
140 dst_path / "static",
141 dst_path / "static" / "build",
142 dst_path / "static" / "build" / "style.css",
143 }
146def test_archive_includes_hidden_files_but_excludes_env( 1abcdefg
147 src_path: Path, tar_path: Path, dst_path: Path
148) -> None:
149 """Should include hidden files but exclude .env files."""
150 (src_path / "main.py").write_text("print('hello')") 1CDEFGHI
151 (src_path / ".env").write_text("SECRET_KEY=xyz") 1CDEFGHI
152 (src_path / ".env.local").write_text("LOCAL_KEY=abc") 1CDEFGHI
153 (src_path / ".config").mkdir() 1CDEFGHI
154 (src_path / ".config" / "settings.json").write_text('{"setting": "value"}') 1CDEFGHI
156 archive(src_path, tar_path) 1CDEFGHI
158 with fastar.open(tar_path, "r") as tar: 1CDEFGHI
159 tar.unpack(dst_path) 1CDEFGHI
161 assert set(dst_path.glob("**/*")) == { 1CDEFGHI
162 dst_path / "main.py",
163 dst_path / ".config",
164 dst_path / ".config" / "settings.json",
165 }