huge tests WiP

This commit is contained in:
Jakub Kropáček 2024-05-28 15:35:47 +02:00
parent bcef4ff794
commit d7884d5627
17 changed files with 149 additions and 48 deletions

3
.gitignore vendored
View file

@ -32,7 +32,8 @@ dmypy.json
# PyCharm # PyCharm
.idea/ .idea/
# tests poetry install # tests
.nox/
.tox/ .tox/
.coverage .coverage

View file

@ -25,12 +25,16 @@ class Source(NamedTuple):
class Config(NamedTuple): class Config(NamedTuple):
output_dir: str | Path output_dir: str | Path
sources_configs: dict[str, Source] | None sources_configs: dict[str, Source] | dict
@classmethod @classmethod
def from_dict(cls, _dict: dict[str, Any]) -> Self: def from_dict(cls, _dict: dict[str, Any]) -> Self:
output_dir = _dict.get("config").get("output_dir", None)
sources = {name: Source.from_dict(src) for name, src in _dict.get("sources").items()} if not (cfg := _dict.get("config")):
raise errors.InvalidConfig("`[config]` cannot be empty!")
output_dir = cfg.get("output_dir", None)
sources = {name: Source.from_dict(src) for name, src in _dict.get("sources", dict()).items()}
if not output_dir: if not output_dir:
raise errors.InvalidConfig("`output_dir` needs to be specified!") raise errors.InvalidConfig("`output_dir` needs to be specified!")
cfg = cls(output_dir=output_dir, sources_configs=sources) cfg = cls(output_dir=output_dir, sources_configs=sources)

View file

@ -11,3 +11,8 @@ class InvalidConfig(Exception):
class InvalidSource(Exception): class InvalidSource(Exception):
"""Raised when invalid source is used""" """Raised when invalid source is used"""
pass pass
class HTTPError(Exception):
"""Raised when API rejects our request"""
pass

View file

@ -1,13 +1,4 @@
import importlib from .utils import get
from . import github
from . import base from . import gitlab
from .. import errors from . import gitlab_group
def get(source_name: str) -> type[base.BaseSource]:
try:
module = importlib.import_module(f"many_repos.source_type.{source_name}")
return module.Source
except (ModuleNotFoundError, AttributeError):
raise errors.InvalidSource(f"Source {source_name} not found!")

View file

@ -1,8 +1,9 @@
import abc import abc
import json import json
from http.client import HTTPResponse
from urllib import request from urllib import request
from many_repos import common from many_repos import common, errors
from many_repos import config from many_repos import config
@ -36,6 +37,9 @@ class BaseSource(abc.ABC):
""" """
Helper function to create http requests using urllib Helper function to create http requests using urllib
""" """
if not headers:
headers = dict()
if body: if body:
headers["Content-Type"] = "application/json" headers["Content-Type"] = "application/json"
data = json.dumps(body).encode('utf-8') data = json.dumps(body).encode('utf-8')
@ -48,5 +52,12 @@ class BaseSource(abc.ABC):
headers=headers, headers=headers,
data=data data=data
) )
res = request.urlopen(req)
res: HTTPResponse = request.urlopen(req)
if 400 <= res.status < 500:
raise errors.HTTPError(f"Client failed to make http request: {res.reason}")
if 500 <= res.status < 600:
raise errors.HTTPError(f"Server failed to respond to our request: {res.reason}")
return json.load(res) return json.load(res)

View file

@ -11,13 +11,13 @@ class Source(BaseSource):
for repo in repos_json: for repo in repos_json:
if not self.source_config.forks and repo.get("fork"): if not self.source_config.forks and repo.get("fork"):
continue continue
namespace, name = repo.get("full_name").split("/", 2) namespace, name = repo["full_name"].split("/", 2)
repositories.append( repositories.append(
common.Repository( common.Repository(
name=name, name=name,
namespace=namespace, namespace=namespace,
url=repo.get("ssh_url"), url=repo["ssh_url"],
fork=repo.get("fork"), fork=repo["fork"],
vcs="github.com" vcs="github.com"
) )
) )

View file

@ -7,13 +7,13 @@ class Source(BaseSource):
repos_json = self._make_request(self._api_url, headers=self._headers) repos_json = self._make_request(self._api_url, headers=self._headers)
repositories = [] repositories = []
for repo in repos_json: for repo in repos_json:
namespace, name = repo.get("path_with_namespace").split("/") namespace, name = repo["path_with_namespace"].split("/")
repositories.append( repositories.append(
common.Repository( common.Repository(
name=name, name=name,
namespace=namespace, namespace=namespace,
url=repo.get("ssh_url_to_repo"), url=repo["ssh_url_to_repo"],
fork=bool(repo.get("forked_from_project")), fork=bool(repo["forked_from_project"]),
vcs="gitlab.com" vcs="gitlab.com"
) )
) )

View file

@ -0,0 +1,12 @@
import importlib
from . import base
from .. import errors
def get(source_name: str) -> type[base.BaseSource]:
try:
module = importlib.import_module(f"many_repos.source_type.{source_name}")
return module.Source
except (ModuleNotFoundError, AttributeError):
raise errors.InvalidSource(f"Source {source_name} not found!")

View file

@ -9,11 +9,11 @@ def tests(s):
s.run('pytest', 'tests') s.run('pytest', 'tests')
@session(python='python3.12') @session(python='python3.12', name="type")
def _type(s): def _type(s):
"""run type checks""" """run type checks"""
s.install('mypy') s.install('mypy')
s.run('mypy', 'many_repos', 'tests') s.run('mypy', 'many_repos')
@session(python='python3.12') @session(python='python3.12')

View file

@ -16,7 +16,6 @@ many-repos-clone = "many_repos.clone:main"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.11" python = "^3.11"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = "^8.2.1" pytest = "^8.2.1"
ruff = "^0.4.5" ruff = "^0.4.5"

8
tests/common_test.py Normal file
View file

@ -0,0 +1,8 @@
from pathlib import Path
from many_repos.clone import _construct_path
def test_correct_construct_path(test_repo, many_repos_config):
assert _construct_path(test_repo, many_repos_config) == (
Path(many_repos_config.output_dir) / test_repo.vcs / test_repo.namespace / test_repo.name).resolve()

0
tests/config_test.py Normal file
View file

67
tests/conftest.py Normal file
View file

@ -0,0 +1,67 @@
import pytest
from many_repos.common import Repository
from many_repos.config import Source, Config
@pytest.fixture(params=[True, False])
def source_config(request):
return Source(
source_type="github",
username="JustScreaMy",
token="testToken",
forks=request.param
)
@pytest.fixture
def test_repo():
return Repository(
name="many-repos",
namespace="JustScreaMy",
url="git@github.com/JustScreaMy/many-repos.git",
fork=False,
vcs="github.com"
)
@pytest.fixture
def many_repos_config():
return Config(
output_dir="/tmp/test/repos",
sources_configs={
"gitlab": Source(
source_type="gitlab",
username="JustScreaMy",
token="testToken",
forks=False
),
"github": Source(
source_type="github",
username="JustScreaMy",
token="testTokasden",
forks=False
)
}
)
@pytest.fixture
def invalid_many_repos_config():
return Config(
output_dir="/tmp/test/repos",
sources_configs={
"gitlab": Source(
source_type="gitlab",
username="JustScreaMy",
token="testToken",
forks=False
),
"bitbucket": Source(
source_type="bitbucket",
username="JustScreaMy",
token="testTokasden",
forks=False
)
}
)

View file

@ -1,3 +0,0 @@
class TestDummy:
def test_dummy(self):
assert 1 == 1

View file

@ -1,13 +0,0 @@
import pytest
from many_repos.config import Source
@pytest.fixture(params=[True, False])
def source_config(request):
return Source(
source_type="github",
username="JustScreaMy",
token="testToken",
forks=request.param
)

View file

@ -1,7 +1,5 @@
from many_repos.source_type.github import Source as GithubSource from many_repos.source_type.github import Source as GithubSource
from unittest import mock
class TestGithubSource: def dummy():
def test_api_url_generation(self, source_config, monkeypatch): assert 1 == 1
src = GithubSource(source_config)

View file

@ -0,0 +1,21 @@
import pytest
from many_repos import errors
from many_repos import source_type
@pytest.mark.parametrize(
"source, source_model",
(
("gitlab", source_type.gitlab.Source),
("gitlab_group", source_type.gitlab_group.Source),
("github", source_type.github.Source)
)
)
def test_correct_source_model(source, source_model):
assert source_type.get(source) == source_model
def test_invalid_source_model():
with pytest.raises(errors.InvalidSource):
source_type.get("bitbucket")