Skip to content

Commit 8a74ee8

Browse files
committed
some tests
1 parent 2f78bd6 commit 8a74ee8

File tree

17 files changed

+549
-24
lines changed

17 files changed

+549
-24
lines changed

validity/api/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def model_perms(*permissions: str) -> type[BasePermission]:
6060

6161
class Permission(BasePermission):
6262
def has_permission(self, request, view):
63-
return request.user.is_authenticated and request.user.has_perms([permissions])
63+
return request.user.is_authenticated and request.user.has_perms(permissions)
6464

6565
return Permission
6666

validity/data_backup/backupers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class GitBackuper(Backuper):
3939

4040
def _get_repo(self, url: str, parameters: GitParams, datasource_dir: Path) -> RemoteGitRepo:
4141
return RemoteGitRepo(
42-
local_path=datasource_dir,
42+
local_path=str(datasource_dir),
4343
remote_url=url,
4444
active_branch=parameters.branch,
4545
username=parameters.username,

validity/integrations/errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ def __str__(self):
1515
def __repr__(self):
1616
if self.orig_error:
1717
return repr(self.orig_error)
18-
return super().__repr__(self)
18+
return super().__repr__()

validity/integrations/git.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ def clone(
2525
) -> None: ...
2626

2727
@abstractmethod
28-
def stage_all(self, repo_path: str) -> None: ...
28+
def stage_all(self, local_path: str) -> None: ...
2929

3030
@abstractmethod
3131
def unstage_all(self, local_path: str) -> None: ...
3232

3333
@abstractmethod
34-
def commit(self, repo_path: str, username: str, email: str, message: str) -> str:
34+
def commit(self, local_path: str, username: str, email: str, message: str) -> str:
3535
"""
3636
Returns SHA1 hash of the new commit
3737
"""
@@ -67,11 +67,11 @@ def clone(
6767
with reraise(Exception, IntegrationError):
6868
porcelain.clone(remote_url, local_path, checkout=checkout, **optional_args)
6969

70-
def stage_all(self, repo_path: str) -> None:
71-
repo = Repo(repo_path)
70+
def stage_all(self, local_path: str) -> None:
71+
repo = Repo(local_path)
7272
ignore_mgr = IgnoreFilterManager.from_repo(repo)
73-
unstaged_files = (fn.decode() for fn in get_unstaged_changes(repo.open_index(), repo_path))
74-
untracked_files = porcelain.get_untracked_paths(repo_path, repo_path, repo.open_index())
73+
unstaged_files = (fn.decode() for fn in get_unstaged_changes(repo.open_index(), local_path))
74+
untracked_files = porcelain.get_untracked_paths(local_path, local_path, repo.open_index())
7575
files = (file for file in chain(unstaged_files, untracked_files) if not ignore_mgr.is_ignored(file))
7676
repo.stage(files)
7777

@@ -80,9 +80,9 @@ def unstage_all(self, local_path: str) -> None:
8080
staged_files = chain.from_iterable(porcelain.status(local_path).staged.values())
8181
repo.unstage(filename.decode() for filename in staged_files)
8282

83-
def commit(self, repo_path: str, username: str, email: str, message: str) -> str:
83+
def commit(self, local_path: str, username: str, email: str, message: str) -> str:
8484
author = f"{username} <{email}>".encode()
85-
commit_hash = porcelain.commit(repo=repo_path, author=author, committer=author, message=message.encode())
85+
commit_hash = porcelain.commit(repo=local_path, author=author, committer=author, message=message.encode())
8686
return commit_hash.decode()
8787

8888
def push(

validity/models/backup.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from validity import di
1212
from validity.choices import BackupMethodChoices, BackupStatusChoices
1313
from validity.data_backup import BackupBackend
14-
from validity.fields import EncryptedDict, EncryptedDictField
14+
from validity.fields import EncryptedDictField
1515
from validity.subforms import GitBackupForm, S3BackupForm
1616
from .base import BaseModel, SubformMixin
1717
from .data import VDataSource
@@ -79,9 +79,7 @@ def get_last_status_color(self):
7979
return BackupStatusChoices.colors.get(self.last_status)
8080

8181
def serialize_object(self, exclude=None):
82-
if not isinstance(self.parameters, EncryptedDict):
83-
do_not_encrypt = self._meta.get_field("parameters").do_not_encrypt
84-
self.parameters = EncryptedDict(self.parameters, do_not_encrypt=do_not_encrypt)
82+
self.parameters = self._meta.get_field("parameters").to_python(self.parameters)
8583
return super().serialize_object(exclude)
8684

8785
def do_backup(self) -> None:

validity/scripts/keeper.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ def __enter__(self):
2525
return self
2626

2727
def __exit__(self, exc_type, exc, tb):
28-
if exc_type:
29-
self.terminate_errored_job(exc)
30-
elif self.job.status == JobStatusChoices.STATUS_RUNNING and self.auto_terminate:
31-
self.terminate_job()
32-
self.logger.flush()
28+
with self.logger:
29+
if exc_type:
30+
return self.terminate_errored_job(exc)
31+
elif self.job.status == JobStatusChoices.STATUS_RUNNING and self.auto_terminate:
32+
self.terminate_job()
3333

34-
def terminate_errored_job(self, error: Exception) -> None:
34+
def terminate_errored_job(self, error: Exception) -> bool:
3535
if isinstance(error, AbortScript):
3636
self.logger.messages.extend(error.logs)
3737
self.logger.failure(str(error))
@@ -41,6 +41,7 @@ def terminate_errored_job(self, error: Exception) -> None:
4141
status = JobStatusChoices.STATUS_ERRORED
4242
self.error_callback(self, error)
4343
self.terminate_job(status=status, error=repr(error))
44+
return isinstance(error, AbortScript)
4445

4546
def terminate_job(
4647
self, status: str = JobStatusChoices.STATUS_COMPLETED, error: str | None = None, output=None

validity/tests/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from core.models import DataSource
55
from dcim.models import Device, DeviceType, Manufacturer
66
from django.contrib.contenttypes.models import ContentType
7+
from django.utils import timezone
78
from extras.models import CustomField
89
from graphene_django.utils.testing import graphql_query
910
from tenancy.models import Tenant
@@ -88,3 +89,11 @@ def func(*args, **kwargs):
8889
@pytest.fixture
8990
def di():
9091
return validity.di
92+
93+
94+
@pytest.fixture
95+
def timezone_now(monkeypatch):
96+
def _now(tz):
97+
monkeypatch.setattr(timezone, "now", lambda: tz)
98+
99+
return _now

validity/tests/factories.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from validity import models
1515
from validity.compliance.state import StateItem
16+
from validity.fields.encrypted import EncryptedDict
1617

1718

1819
DJANGO_MAJOR_VERSION = django.VERSION[:2]
@@ -28,6 +29,10 @@ class Meta:
2829
model = models.VDataSource
2930

3031

32+
class PollingDSFactory(DataSourceFactory):
33+
type = "device_polling"
34+
35+
3136
class DataFileFactory(DjangoModelFactory):
3237
source = factory.SubFactory(DataSourceFactory)
3338
path = factory.Sequence(lambda n: f"file-{n}.txt")
@@ -236,6 +241,18 @@ class Meta:
236241
model = models.Poller
237242

238243

244+
class BackupPointFactory(DjangoModelFactory):
245+
name = factory.sequence(lambda n: f"bp-{n}")
246+
data_source = factory.SubFactory(PollingDSFactory)
247+
backup_after_sync = False
248+
method = "git"
249+
url = "https://site.com/project"
250+
parameters = EncryptedDict({"username": "a", "password": "b"})
251+
252+
class Meta:
253+
model = models.BackupPoint
254+
255+
239256
class UserFactory(DjangoModelFactory):
240257
241258
username = "su"
@@ -261,6 +278,18 @@ class Meta:
261278
model = Job
262279

263280

281+
class DSBackupJobFactory(DjangoModelFactory):
282+
name = "DataSourcebackup"
283+
object = factory.SubFactory(BackupPointFactory)
284+
object_id = factory.SelfAttribute("object.pk")
285+
object_type = factory.LazyAttribute(lambda obj: ContentType.objects.get_for_model(type(obj.object)))
286+
user = factory.SubFactory(UserFactory)
287+
job_id = factory.LazyFunction(uuid.uuid4)
288+
289+
class Meta:
290+
model = Job
291+
292+
264293
_NOT_DEFINED = object()
265294

266295

validity/tests/test_api.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
import pytest
55
from base import ApiGetTest, ApiPostGetTest
66
from factories import (
7+
BackupPointFactory,
78
CommandFactory,
89
CompTestDBFactory,
910
CompTestResultFactory,
1011
DataFileFactory,
1112
DataSourceFactory,
1213
DeviceFactory,
1314
DeviceTypeFactory,
15+
DSBackupJobFactory,
1416
LocationFactory,
1517
ManufacturerFactory,
1618
PlatformFactory,
19+
PollingDSFactory,
1720
ReportFactory,
1821
RunTestsJobFactory,
1922
SelectorFactory,
@@ -26,6 +29,7 @@
2629

2730
from validity import dependencies
2831
from validity.models import VDevice
32+
from validity.scripts import Launcher
2933

3034

3135
class TestDBNameSet(ApiPostGetTest):
@@ -173,6 +177,29 @@ class TestPoller(ApiPostGetTest):
173177
}
174178

175179

180+
class TestBackupPoint(ApiPostGetTest):
181+
entity = "backup-points"
182+
post_body = {
183+
"name": "bp",
184+
"data_source": PollingDSFactory,
185+
"backup_after_sync": False,
186+
"method": "git",
187+
"upload_url": "http://ex.com/qwer",
188+
"parameters": {"username": "abc", "password": "123"},
189+
}
190+
191+
@pytest.mark.django_db
192+
def test_backup(self, admin_client, di):
193+
bp = BackupPointFactory()
194+
url = self.url(bp.pk) + "backup/"
195+
launcher = Mock(spec=Launcher, return_value=DSBackupJobFactory())
196+
with di.override({dependencies.backup_launcher: lambda: launcher}):
197+
resp = admin_client.post(url)
198+
assert resp.status_code == HTTPStatus.OK
199+
assert resp.json()["result"]["id"] == launcher.return_value.pk
200+
launcher.assert_called_once()
201+
202+
176203
@pytest.mark.parametrize("params", [{}, {"fields": ["name", "value"]}, {"name": ["config", "bad_cmd"]}])
177204
@pytest.mark.django_db
178205
def test_get_serialized_state(admin_client, params, monkeypatch):

0 commit comments

Comments
 (0)