Skip to content

Commit 7616c91

Browse files
xmunozewdurbin
authored andcommitted
Refactor testing logic #7098 (#7257)
- Add `schedule` field to MalwareCheck model #7096 - Move ExampleCheck into tests/common/ to remove test dependency from prod code - Rename functions and classes to differentiate between "hooked" and "scheduled" checks
1 parent 148fcea commit 7616c91

File tree

13 files changed

+244
-119
lines changed

13 files changed

+244
-119
lines changed

tests/common/checks/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
13+
from .hooked import ExampleHookedCheck # noqa
14+
from .scheduled import ExampleScheduledCheck # noqa

warehouse/malware/checks/example.py renamed to tests/common/checks/hooked.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@
1414
from warehouse.malware.models import VerdictClassification, VerdictConfidence
1515

1616

17-
class ExampleCheck(MalwareCheckBase):
17+
class ExampleHookedCheck(MalwareCheckBase):
1818

1919
version = 1
2020
short_description = "An example hook-based check"
21-
long_description = """The purpose of this check is to demonstrate the \
22-
implementation of a hook-based check. This check will generate verdicts if enabled."""
21+
long_description = "The purpose of this check is to test the \
22+
implementation of a hook-based check. This check will generate verdicts if enabled."
2323
check_type = "event_hook"
2424
hooked_object = "File"
2525

2626
def __init__(self, db):
2727
super().__init__(db)
2828

29-
def scan(self, file_id):
29+
def scan(self, file_id=None):
3030
self.add_verdict(
3131
file_id=file_id,
3232
classification=VerdictClassification.benign,

tests/common/checks/scheduled.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
13+
from warehouse.malware.checks.base import MalwareCheckBase
14+
from warehouse.malware.models import VerdictClassification, VerdictConfidence
15+
from warehouse.packaging.models import Project
16+
17+
18+
class ExampleScheduledCheck(MalwareCheckBase):
19+
20+
version = 1
21+
short_description = "An example scheduled check"
22+
long_description = "The purpose of this check is to test the \
23+
implementation of a scheduled check. This check will generate verdicts if enabled."
24+
check_type = "scheduled"
25+
schedule = {"minute": "0", "hour": "*/8"}
26+
27+
def __init__(self, db):
28+
super().__init__(db)
29+
30+
def scan(self):
31+
project = self.db.query(Project).first()
32+
self.add_verdict(
33+
project_id=project.id,
34+
classification=VerdictClassification.benign,
35+
confidence=VerdictConfidence.High,
36+
message="Nothing to see here!",
37+
)

tests/common/db/malware.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class Meta:
3939
long_description = factory.fuzzy.FuzzyText(length=300)
4040
check_type = factory.fuzzy.FuzzyChoice(list(MalwareCheckType))
4141
hooked_object = factory.fuzzy.FuzzyChoice(list(MalwareCheckObjectType))
42+
schedule = {"minute": "*/10"}
4243
state = factory.fuzzy.FuzzyChoice(list(MalwareCheckState))
4344
created = factory.fuzzy.FuzzyNaiveDateTime(
4445
datetime.datetime.utcnow() - datetime.timedelta(days=7)

tests/unit/malware/test_checks.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,35 @@
1212

1313
import inspect
1414

15-
import warehouse.malware.checks as checks
15+
import pytest
16+
17+
import warehouse.malware.checks as prod_checks
1618

1719
from warehouse.malware.checks.base import MalwareCheckBase
1820
from warehouse.malware.utils import get_check_fields
1921

22+
from ...common import checks as test_checks
23+
2024

2125
def test_checks_subclass_base():
22-
checks_from_module = inspect.getmembers(checks, inspect.isclass)
26+
prod_checks_from_module = inspect.getmembers(prod_checks, inspect.isclass)
27+
test_checks_from_module = inspect.getmembers(test_checks, inspect.isclass)
28+
all_checks = prod_checks_from_module + test_checks_from_module
2329

2430
subclasses_of_malware_base = {
2531
cls.__name__: cls for cls in MalwareCheckBase.__subclasses__()
2632
}
2733

28-
assert len(checks_from_module) == len(subclasses_of_malware_base)
34+
assert len(all_checks) == len(subclasses_of_malware_base)
2935

30-
for check_name, check in checks_from_module:
36+
for check_name, check in all_checks:
3137
assert subclasses_of_malware_base[check_name] == check
3238

3339

34-
def test_checks_fields():
40+
@pytest.mark.parametrize(
41+
("checks"), [prod_checks, test_checks],
42+
)
43+
def test_checks_fields(checks):
3544
checks_from_module = inspect.getmembers(checks, inspect.isclass)
3645

3746
for check_name, check in checks_from_module:

tests/unit/malware/test_init.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@
1818
from warehouse.malware import utils
1919
from warehouse.malware.interfaces import IMalwareCheckService
2020

21+
from ...common import checks as test_checks
2122
from ...common.db.accounts import UserFactory
2223
from ...common.db.packaging import FileFactory, ProjectFactory, ReleaseFactory
2324

2425

2526
def test_determine_malware_checks_no_checks(monkeypatch, db_request):
26-
def get_enabled_checks(session):
27+
def get_enabled_hooked_checks(session):
2728
return defaultdict(list)
2829

29-
monkeypatch.setattr(utils, "get_enabled_checks", get_enabled_checks)
30+
monkeypatch.setattr(utils, "get_enabled_hooked_checks", get_enabled_hooked_checks)
3031

3132
project = ProjectFactory.create(name="foo")
3233
release = ReleaseFactory.create(project=project)
@@ -39,13 +40,13 @@ def get_enabled_checks(session):
3940

4041

4142
def test_determine_malware_checks_nothing_new(monkeypatch, db_request):
42-
def get_enabled_checks(session):
43+
def get_enabled_hooked_checks(session):
4344
result = defaultdict(list)
4445
result["File"] = ["Check1", "Check2"]
4546
result["Release"] = ["Check3"]
4647
return result
4748

48-
monkeypatch.setattr(utils, "get_enabled_checks", get_enabled_checks)
49+
monkeypatch.setattr(utils, "get_enabled_hooked_checks", get_enabled_hooked_checks)
4950

5051
project = ProjectFactory.create(name="foo")
5152
release = ReleaseFactory.create(project=project)
@@ -58,13 +59,13 @@ def get_enabled_checks(session):
5859

5960

6061
def test_determine_malware_checks_unsupported_object(monkeypatch, db_request):
61-
def get_enabled_checks(session):
62+
def get_enabled_hooked_checks(session):
6263
result = defaultdict(list)
6364
result["File"] = ["Check1", "Check2"]
6465
result["Release"] = ["Check3"]
6566
return result
6667

67-
monkeypatch.setattr(utils, "get_enabled_checks", get_enabled_checks)
68+
monkeypatch.setattr(utils, "get_enabled_hooked_checks", get_enabled_hooked_checks)
6869

6970
user = UserFactory.create()
7071

@@ -75,13 +76,13 @@ def get_enabled_checks(session):
7576

7677

7778
def test_determine_malware_checks_file_only(monkeypatch, db_request):
78-
def get_enabled_checks(session):
79+
def get_enabled_hooked_checks(session):
7980
result = defaultdict(list)
8081
result["File"] = ["Check1", "Check2"]
8182
result["Release"] = ["Check3"]
8283
return result
8384

84-
monkeypatch.setattr(utils, "get_enabled_checks", get_enabled_checks)
85+
monkeypatch.setattr(utils, "get_enabled_hooked_checks", get_enabled_hooked_checks)
8586

8687
project = ProjectFactory.create(name="foo")
8788
release = ReleaseFactory.create(project=project)
@@ -95,13 +96,13 @@ def get_enabled_checks(session):
9596

9697

9798
def test_determine_malware_checks_file_and_release(monkeypatch, db_request):
98-
def get_enabled_checks(session):
99+
def get_enabled_hooked_checks(session):
99100
result = defaultdict(list)
100101
result["File"] = ["Check1", "Check2"]
101102
result["Release"] = ["Check3"]
102103
return result
103104

104-
monkeypatch.setattr(utils, "get_enabled_checks", get_enabled_checks)
105+
monkeypatch.setattr(utils, "get_enabled_hooked_checks", get_enabled_hooked_checks)
105106

106107
project = ProjectFactory.create(name="foo")
107108
release = ReleaseFactory.create(project=project)
@@ -149,7 +150,9 @@ def test_enqueue_malware_checks_no_checks(app_config):
149150
assert "warehouse.malware.checks" not in session.info
150151

151152

152-
def test_includeme():
153+
def test_includeme(monkeypatch):
154+
monkeypatch.setattr(malware, "checks", test_checks)
155+
153156
malware_check_class = pretend.stub(
154157
create_service=pretend.call_recorder(lambda *a, **kw: pretend.stub())
155158
)

0 commit comments

Comments
 (0)