Skip to content

Commit

Permalink
add: unit tests for updater (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
metaist committed Sep 15, 2024
1 parent 591a929 commit 0629e99
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 7 deletions.
5 changes: 3 additions & 2 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
"cosmofy",
"fpclose",
"levelname",
"metaist",
"mypy",
"parsedate",
"pdoc",
"pypa",
"pypi",
"pyright",
"pytest",
"setuptools",
"venv",
"zinfo",
"metaist"
"zinfo"
]
}
5 changes: 3 additions & 2 deletions src/cosmofy/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ def download(url: str, path: Path, chunk_size: int = CHUNK_SIZE) -> Path:

def download_if_newer(url: str, path: Path, chunk_size: int = CHUNK_SIZE) -> Path:
"""Download `url` to `path` if `url` is newer."""
need_download = not path.exists() # guess: exists => already downloaded
if path.exists():
exists = path.exists()
need_download = not exists # guess: exists => already downloaded
if exists:
local = datetime.fromtimestamp(path.stat().st_mtime, tz=timezone.utc)
response = urlopen(Request(url, method="HEAD"))
remote = parsedate_to_datetime(response.headers.get("Last-Modified"))
Expand Down
13 changes: 10 additions & 3 deletions test/test_bundler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
from typing import Iterator
from typing import Set
from typing import Tuple
from unittest.mock import patch
import io
import os
import tempfile

# pkg
from cosmofy import bundler
from cosmofy.args import Args
from cosmofy.args import COSMOFY_PYTHON_URL
from cosmofy.bundler import _archive
from cosmofy.bundler import _pack_uint32
from cosmofy.bundler import Bundler
Expand Down Expand Up @@ -108,10 +110,15 @@ def test_from_download() -> None:
src, dest = Path(f.name), Path(g.name)

test.from_cache(src, dest)
real.from_cache(src, dest)

test.from_download(dest)
real.from_download(dest)

with patch("cosmofy.bundler.Bundler.fs_copy") as mock:
real.from_cache(src, dest)
mock.assert_called_once_with(src, dest)

with patch("cosmofy.bundler.download") as mock:
real.from_download(dest)
mock.assert_called_once_with(COSMOFY_PYTHON_URL, dest)


def test_setup_temp() -> None:
Expand Down
118 changes: 118 additions & 0 deletions test/test_updater.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""Updater."""

# std
from datetime import datetime
from datetime import timezone
from pathlib import Path
from unittest.mock import MagicMock
from unittest.mock import patch

# pkg
from cosmofy import updater


@patch("cosmofy.updater.urlopen")
@patch("cosmofy.updater.Path.open")
@patch("cosmofy.updater.Path.mkdir")
def test_download(_mkdir: MagicMock, _open: MagicMock, _urlopen: MagicMock) -> None:
"""Download url."""
# read url
_response = MagicMock()
_response.read.side_effect = [b"chunk1", b"chunk2", b""]
_urlopen.return_value.__enter__.return_value = _response

# open file
_output = MagicMock()
_open.return_value.__enter__.return_value = _output

# test
url = "http://example.com"
path = Path("fake")
result = updater.download(url, path)

_urlopen.assert_called_once_with(url)
_mkdir.assert_called_once_with(parents=True, exist_ok=True)
_output.write.assert_any_call(b"chunk1")
_output.write.assert_any_call(b"chunk2")
assert result == path


@patch("cosmofy.updater.Path.exists")
@patch("cosmofy.updater.download")
def test_download_if_not_exists(_download: MagicMock, _exists: MagicMock) -> None:
"""Call download when there's no file."""
# local
_exists.return_value = False # file does not exist

# test
url = "http://example.com"
path = Path("fake")
updater.download_if_newer(url, path)

_download.assert_called()


@patch("cosmofy.updater.Path.exists")
@patch("cosmofy.updater.Path.stat")
@patch("cosmofy.updater.urlopen")
@patch("cosmofy.updater.parsedate_to_datetime")
@patch("cosmofy.updater.download")
def test_download_if_newer(
_download: MagicMock,
_parsedate: MagicMock,
_urlopen: MagicMock,
_stat: MagicMock,
_exists: MagicMock,
) -> None:
"""Call download if there's a newer version."""
# local
_exists.return_value = True # File exists
_stat.return_value.st_mtime = datetime(2023, 9, 1, tzinfo=timezone.utc).timestamp()
_stat.return_value.st_mode = 33204 # for Path.open

# remote
_response = MagicMock()
_response.headers.get.return_value = "Wed, 02 Sep 2023 00:00:00 GMT"
_response.read.side_effect = [b"chunk1", b"chunk2", b""]
_urlopen.return_value.__enter__.return_value = _response
_parsedate.return_value = datetime(2023, 9, 2, tzinfo=timezone.utc)

# test
url = "http://example.com"
path = Path("fake")
updater.download_if_newer(url, path)

assert _urlopen.called
assert _download.called


@patch("cosmofy.updater.Path.exists")
@patch("cosmofy.updater.Path.stat")
@patch("cosmofy.updater.urlopen")
@patch("cosmofy.updater.parsedate_to_datetime")
@patch("cosmofy.updater.download")
def test_download_if_not_newer(
_download: MagicMock,
_parsedate: MagicMock,
_urlopen: MagicMock,
_stat: MagicMock,
_exists: MagicMock,
) -> None:
# local
_exists.return_value = True # File exists
_stat.return_value.st_mtime = datetime(2023, 9, 2, tzinfo=timezone.utc).timestamp()

# remote
_response = MagicMock()
_response.headers.get.return_value = "Wed, 01 Sep 2023 00:00:00 GMT"
_urlopen.return_value.__enter__.return_value = _response
_parsedate.return_value = datetime(2023, 9, 1, tzinfo=timezone.utc)

# test
url = "http://example.com"
path = Path("path")
result = updater.download_if_newer(url, path)

_urlopen.assert_called_once()
_download.assert_not_called()
assert result == path

0 comments on commit 0629e99

Please sign in to comment.