Skip to content

Commit 7d87c9d

Browse files
authored
Feature/more tests (#8)
* Fix loading vulnerability * Add more tests * Add is_empty * Split test files * Improve tests * Add team tests
1 parent a1adc56 commit 7d87c9d

15 files changed

Lines changed: 340 additions & 40 deletions

owasp_dt/models/vulnerability.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ class Vulnerability:
3333
Attributes:
3434
vuln_id (str):
3535
source (str):
36-
friendly_vuln_id (str):
3736
uuid (UUID):
37+
friendly_vuln_id (Union[Unset, str]):
3838
title (Union[Unset, str]):
3939
sub_title (Union[Unset, str]):
4040
description (Union[Unset, str]):
@@ -76,8 +76,8 @@ class Vulnerability:
7676

7777
vuln_id: str
7878
source: str
79-
friendly_vuln_id: str
8079
uuid: UUID
80+
friendly_vuln_id: Union[Unset, str] = UNSET
8181
title: Union[Unset, str] = UNSET
8282
sub_title: Union[Unset, str] = UNSET
8383
description: Union[Unset, str] = UNSET
@@ -122,10 +122,10 @@ def to_dict(self) -> dict[str, Any]:
122122

123123
source = self.source
124124

125-
friendly_vuln_id = self.friendly_vuln_id
126-
127125
uuid = str(self.uuid)
128126

127+
friendly_vuln_id = self.friendly_vuln_id
128+
129129
title = self.title
130130

131131
sub_title = self.sub_title
@@ -243,10 +243,11 @@ def to_dict(self) -> dict[str, Any]:
243243
{
244244
"vulnId": vuln_id,
245245
"source": source,
246-
"friendlyVulnId": friendly_vuln_id,
247246
"uuid": uuid,
248247
}
249248
)
249+
if friendly_vuln_id is not UNSET:
250+
field_dict["friendlyVulnId"] = friendly_vuln_id
250251
if title is not UNSET:
251252
field_dict["title"] = title
252253
if sub_title is not UNSET:
@@ -342,10 +343,10 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
342343

343344
source = d.pop("source")
344345

345-
friendly_vuln_id = d.pop("friendlyVulnId")
346-
347346
uuid = UUID(d.pop("uuid"))
348347

348+
friendly_vuln_id = d.pop("friendlyVulnId", UNSET)
349+
349350
title = d.pop("title", UNSET)
350351

351352
sub_title = d.pop("subTitle", UNSET)
@@ -482,8 +483,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
482483
vulnerability = cls(
483484
vuln_id=vuln_id,
484485
source=source,
485-
friendly_vuln_id=friendly_vuln_id,
486486
uuid=uuid,
487+
friendly_vuln_id=friendly_vuln_id,
487488
title=title,
488489
sub_title=sub_title,
489490
description=description,

patch.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
}
134134
},
135135
"Vulnerability": {
136+
"required" : [ "source", "uuid", "vulnId" ],
136137
"properties": {
137138
"findingAttribution": {
138139
"$ref": "#/components/schemas/FindingAttrib"

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ test = [
2424
"pytest>=7",
2525
"pytest-depends",
2626
"pytest-cov",
27-
"dotenv",
27+
"dotenv== 0.9.9",
2828
"openapi-python-client",
29+
"tinystream==0.1.18",
30+
"is_empty==1.0.1",
2931
]

schema.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15231,7 +15231,6 @@
1523115231
},
1523215232
"Vulnerability": {
1523315233
"required": [
15234-
"friendlyVulnId",
1523515234
"source",
1523615235
"uuid",
1523715236
"vulnId"

test/__init__.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,43 @@
1+
import math
2+
import time
13
from pathlib import Path
4+
from typing import Callable
25

36
from dotenv import load_dotenv
4-
from owasp_dt import Client
5-
import owasp_dt
7+
68
from test import config
7-
__base_dir = Path(__file__).parent
8-
9-
test_project_name = "test-api"
10-
11-
def create_client_from_env() -> owasp_dt.Client:
12-
base_url = config.reqenv("OWASP_DTRACK_URL")
13-
return Client(
14-
base_url=f"{base_url}/api",
15-
headers={
16-
"X-Api-Key": config.reqenv("OWASP_DTRACK_API_KEY")
17-
},
18-
verify_ssl=config.getenv("OWASP_DTRACK_VERIFY_SSL", "1", config.parse_true),
19-
raise_on_unexpected_status=False,
20-
httpx_args={
21-
"proxy": config.getenv("HTTPS_PROXY", lambda: config.getenv("HTTP_PROXY", None)),
22-
#"no_proxy": getenv("NO_PROXY", "")
23-
}
24-
)
9+
10+
base_dir = Path(__file__).parent
11+
12+
project_name = "test-api"
13+
upload_token: str | None = None
14+
project_uuid: str | None = None
15+
mit_license_uuid: str | None = None
16+
17+
def retry(callable: Callable, seconds: float, wait_time: float = 3):
18+
retries = math.ceil(seconds / wait_time)
19+
#start_date = datetime.now()
20+
exception = None
21+
ret = None
22+
for i in range(retries):
23+
try:
24+
exception = None
25+
ret = callable()
26+
break
27+
except Exception as e:
28+
exception = e
29+
time.sleep(wait_time)
30+
31+
if exception:
32+
raise exception
33+
#raise Exception(f"{exception} after {datetime.now()-start_date}")
34+
35+
return ret
36+
2537

2638
def setup_module():
27-
assert load_dotenv(__base_dir / "test.env")
39+
assert load_dotenv(base_dir / "test.env")
40+
2841

2942
def teardown_module():
3043
pass

test/api.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from typing import Generator, Callable, TypeVar
2+
3+
from owasp_dt import Client
4+
from owasp_dt.api.project_property import create_property_1, update_property
5+
from owasp_dt.models import ProjectProperty
6+
from owasp_dt.types import Response
7+
from test import config
8+
9+
10+
def create_client_from_env() -> Client:
11+
base_url = config.reqenv("OWASP_DTRACK_URL")
12+
return Client(
13+
base_url=f"{base_url}/api",
14+
headers={
15+
"X-Api-Key": config.reqenv("OWASP_DTRACK_API_KEY")
16+
},
17+
verify_ssl=config.getenv("OWASP_DTRACK_VERIFY_SSL", "1", config.parse_true),
18+
raise_on_unexpected_status=False,
19+
httpx_args={
20+
"proxy": config.getenv("HTTPS_PROXY", lambda: config.getenv("HTTP_PROXY", None)),
21+
#"no_proxy": getenv("NO_PROXY", "")
22+
}
23+
)
24+
25+
def upsert_project_property(client: Client, uuid: str, property: ProjectProperty):
26+
resp = create_property_1.sync_detailed(client=client, uuid=uuid, body=property)
27+
if resp.status_code == 409:
28+
resp = update_property.sync_detailed(client=client, uuid=uuid, body=property)
29+
30+
assert resp.status_code in [200, 201]
31+
32+
T = TypeVar('T')
33+
34+
def page_result(cb: Callable[[int], Response[list[T]]]) -> Generator[list[T]]:
35+
page_number = 0
36+
while True:
37+
page_number += 1
38+
resp = cb(page_number)
39+
assert resp.status_code == 200
40+
items = resp.parsed
41+
if len(items) == 0:
42+
break
43+
else:
44+
yield items

test/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import pytest
22

3-
from test import create_client_from_env
3+
from test import api
44

55

66
@pytest.fixture
77
def client():
8-
yield create_client_from_env()
8+
yield api.create_client_from_env()

test/files/test.sbom.xml

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

test/test_projects.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import pytest
2+
3+
import owasp_dt
4+
import test
5+
from owasp_dt.api.metrics import get_project_current_metrics
6+
from owasp_dt.api.project import get_projects
7+
8+
9+
@pytest.mark.depends(on=['test/test_upload.py::test_upload_sbom'])
10+
def test_search_project_by_name(client: owasp_dt.Client):
11+
resp = get_projects.sync_detailed(client=client, name=test.project_name)
12+
projects = resp.parsed
13+
assert len(projects) > 0
14+
assert projects[0].uuid is not None
15+
test.project_uuid = projects[0].uuid
16+
17+
@pytest.mark.depends(on=['test/test_upload.py::test_get_scan_status', 'test_search_project_by_name'])
18+
def test_get_project_metrics(client: owasp_dt.Client):
19+
resp = get_project_current_metrics.sync_detailed(client=client, uuid=test.project_uuid)
20+
metrics = resp.parsed

test/test_property.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import pytest
2+
from tinystream import Opt
3+
4+
import owasp_dt
5+
import test
6+
from owasp_dt.api.project import get_project
7+
from owasp_dt.models import ProjectPropertyPropertyType, ProjectProperty
8+
from test import api
9+
10+
11+
@pytest.mark.depends(on=['test/test_projects.py::test_search_project_by_name'])
12+
def test_upsert_project_property(client: owasp_dt.Client):
13+
property = ProjectProperty(
14+
group_name="owasp-dtrack-python-client",
15+
property_name="test",
16+
property_type=ProjectPropertyPropertyType.STRING,
17+
property_value="set",
18+
description="Custom property test"
19+
)
20+
api.upsert_project_property(client=client, uuid=test.project_uuid, property=property)
21+
22+
def _filter_property(property:ProjectProperty):
23+
return property.group_name == "owasp-dtrack-python-client" and property.property_name == "test"
24+
25+
resp = get_project.sync_detailed(client=client, uuid=test.project_uuid)
26+
project = resp.parsed
27+
opt_property = Opt(project).map_key("properties").stream().filter(_filter_property).next()
28+
assert opt_property.present
29+
assert opt_property.get().property_value == "set"
30+
31+
property.property_value = "new_value"
32+
api.upsert_project_property(client=client, uuid=test.project_uuid, property=property)
33+
resp = get_project.sync_detailed(client=client, uuid=test.project_uuid)
34+
project = resp.parsed
35+
opt_property = Opt(project).map_key("properties").stream().filter(_filter_property).next()
36+
assert opt_property.present
37+
assert opt_property.get().property_value == "new_value"

0 commit comments

Comments
 (0)