Skip to content

Commit 6e7cdf1

Browse files
committed
pytest_plugin(feat): Add caching to async fixtures
why: Async fixtures should match sync fixture performance pattern what: - Add master_copy caching to async_git_repo fixture - Add async_hg_repo fixture with caching - Add async_svn_repo fixture with caching - Add tests for new async_hg_repo and async_svn_repo fixtures
1 parent 22927f0 commit 6e7cdf1

File tree

3 files changed

+132
-1
lines changed

3 files changed

+132
-1
lines changed

src/libvcs/pytest_plugin.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import pytest_asyncio
2525

2626
from libvcs.sync._async.git import AsyncGitSync
27+
from libvcs.sync._async.hg import AsyncHgSync
28+
from libvcs.sync._async.svn import AsyncSvnSync
2729

2830
HAS_PYTEST_ASYNCIO = True
2931
except ImportError:
@@ -818,10 +820,19 @@ async def async_git_repo(
818820
"""
819821
remote_repo_name = unique_repo_name(remote_repos_path=projects_path)
820822
new_checkout_path = projects_path / remote_repo_name
823+
master_copy = remote_repos_path / "async_git_repo"
824+
825+
if master_copy.exists():
826+
shutil.copytree(master_copy, new_checkout_path)
827+
yield AsyncGitSync(
828+
url=f"file://{git_remote_repo}",
829+
path=new_checkout_path,
830+
)
831+
return
821832

822833
repo = AsyncGitSync(
823834
url=f"file://{git_remote_repo}",
824-
path=new_checkout_path,
835+
path=master_copy,
825836
remotes={
826837
"origin": GitRemote(
827838
name="origin",
@@ -833,6 +844,81 @@ async def async_git_repo(
833844
await repo.obtain()
834845
yield repo
835846

847+
@pytest_asyncio.fixture
848+
@skip_if_hg_missing
849+
async def async_hg_repo(
850+
remote_repos_path: pathlib.Path,
851+
projects_path: pathlib.Path,
852+
hg_remote_repo: pathlib.Path,
853+
set_hgconfig: pathlib.Path,
854+
) -> t.AsyncGenerator[AsyncHgSync, None]:
855+
"""Pre-made async hg clone of remote repo checked out to user's projects dir.
856+
857+
Async equivalent of :func:`hg_repo` fixture.
858+
859+
Examples
860+
--------
861+
>>> @pytest.mark.asyncio
862+
... async def test_hg_operations(async_hg_repo):
863+
... revision = await async_hg_repo.get_revision()
864+
... assert revision is not None
865+
"""
866+
remote_repo_name = unique_repo_name(remote_repos_path=projects_path)
867+
new_checkout_path = projects_path / remote_repo_name
868+
master_copy = remote_repos_path / "async_hg_repo"
869+
870+
if master_copy.exists():
871+
shutil.copytree(master_copy, new_checkout_path)
872+
yield AsyncHgSync(
873+
url=f"file://{hg_remote_repo}",
874+
path=new_checkout_path,
875+
)
876+
return
877+
878+
repo = AsyncHgSync(
879+
url=f"file://{hg_remote_repo}",
880+
path=master_copy,
881+
)
882+
await repo.obtain()
883+
yield repo
884+
885+
@pytest_asyncio.fixture
886+
@skip_if_svn_missing
887+
async def async_svn_repo(
888+
remote_repos_path: pathlib.Path,
889+
projects_path: pathlib.Path,
890+
svn_remote_repo: pathlib.Path,
891+
) -> t.AsyncGenerator[AsyncSvnSync, None]:
892+
"""Pre-made async svn checkout of remote repo checked out to user's projects dir.
893+
894+
Async equivalent of :func:`svn_repo` fixture.
895+
896+
Examples
897+
--------
898+
>>> @pytest.mark.asyncio
899+
... async def test_svn_operations(async_svn_repo):
900+
... revision = await async_svn_repo.get_revision()
901+
... assert revision is not None
902+
"""
903+
remote_repo_name = unique_repo_name(remote_repos_path=projects_path)
904+
new_checkout_path = projects_path / remote_repo_name
905+
master_copy = remote_repos_path / "async_svn_repo"
906+
907+
if master_copy.exists():
908+
shutil.copytree(master_copy, new_checkout_path)
909+
yield AsyncSvnSync(
910+
url=f"file://{svn_remote_repo}",
911+
path=new_checkout_path,
912+
)
913+
return
914+
915+
repo = AsyncSvnSync(
916+
url=f"file://{svn_remote_repo}",
917+
path=master_copy,
918+
)
919+
await repo.obtain()
920+
yield repo
921+
836922

837923
@pytest.fixture
838924
def add_doctest_fixtures(

tests/sync/_async/test_hg.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,25 @@ async def test_get_revision(
124124
revision = await repo.get_revision()
125125
# Mercurial revisions are numeric (0, 1, 2, ...)
126126
assert revision.strip().isdigit() or revision.strip() == ""
127+
128+
129+
class TestAsyncHgRepoFixture:
130+
"""Tests for the async_hg_repo pytest fixture."""
131+
132+
@pytest.mark.asyncio
133+
async def test_async_hg_repo_fixture(
134+
self,
135+
async_hg_repo: AsyncHgSync,
136+
) -> None:
137+
"""Test that async_hg_repo fixture provides a working repository."""
138+
assert async_hg_repo.path.exists()
139+
assert (async_hg_repo.path / ".hg").exists()
140+
141+
@pytest.mark.asyncio
142+
async def test_async_hg_repo_revision(
143+
self,
144+
async_hg_repo: AsyncHgSync,
145+
) -> None:
146+
"""Test async_hg_repo fixture can get revision."""
147+
revision = await async_hg_repo.get_revision()
148+
assert revision.strip().isdigit() or revision.strip() == ""

tests/sync/_async/test_svn.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,26 @@ async def test_get_revision_file(
246246
revision = await repo.get_revision_file("./")
247247
# SVN revisions start at 0 for empty repos
248248
assert revision == 0
249+
250+
251+
class TestAsyncSvnRepoFixture:
252+
"""Tests for the async_svn_repo pytest fixture."""
253+
254+
@pytest.mark.asyncio
255+
async def test_async_svn_repo_fixture(
256+
self,
257+
async_svn_repo: AsyncSvnSync,
258+
) -> None:
259+
"""Test that async_svn_repo fixture provides a working repository."""
260+
assert async_svn_repo.path.exists()
261+
assert (async_svn_repo.path / ".svn").exists()
262+
263+
@pytest.mark.asyncio
264+
async def test_async_svn_repo_revision(
265+
self,
266+
async_svn_repo: AsyncSvnSync,
267+
) -> None:
268+
"""Test async_svn_repo fixture can get revision."""
269+
revision = await async_svn_repo.get_revision()
270+
# SVN revisions start at 0 for empty repos
271+
assert revision == 0

0 commit comments

Comments
 (0)