huge tests WiP
This commit is contained in:
parent
bcef4ff794
commit
d7884d5627
17 changed files with 149 additions and 48 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -32,7 +32,8 @@ dmypy.json
|
||||||
# PyCharm
|
# PyCharm
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
# tests poetry install
|
# tests
|
||||||
|
|
||||||
|
.nox/
|
||||||
.tox/
|
.tox/
|
||||||
.coverage
|
.coverage
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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!")
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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!")
|
|
@ -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')
|
||||||
|
|
|
@ -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
8
tests/common_test.py
Normal 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
0
tests/config_test.py
Normal file
67
tests/conftest.py
Normal file
67
tests/conftest.py
Normal 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
|
@ -1,3 +0,0 @@
|
||||||
class TestDummy:
|
|
||||||
def test_dummy(self):
|
|
||||||
assert 1 == 1
|
|
|
@ -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
|
|
||||||
)
|
|
|
@ -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)
|
|
21
tests/source_type/utils_test.py
Normal file
21
tests/source_type/utils_test.py
Normal 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")
|
Loading…
Reference in a new issue