Enable ado render testing (#1144)

This commit is contained in:
bmc-msft
2021-08-12 12:38:49 -04:00
committed by GitHub
parent 92ce90adb4
commit 5a8a1c998e
6 changed files with 234 additions and 22 deletions

View File

@ -4,7 +4,7 @@
# Licensed under the MIT License.
import logging
from typing import Iterator, List, Optional, Union
from typing import Iterator, List, Optional, Tuple, Union
from azure.devops.connection import Connection
from azure.devops.credentials import BasicAuthentication
@ -60,12 +60,19 @@ class ADO:
filename: str,
config: ADOTemplate,
report: Report,
*,
renderer: Optional[Render] = None,
):
self.config = config
self.renderer = Render(container, filename, report)
if renderer:
self.renderer = renderer
else:
self.renderer = Render(container, filename, report)
self.project = self.render(self.config.project)
def connect(self) -> None:
auth_token = get_secret_string_value(self.config.auth_token)
self.client = get_ado_client(self.config.base_url, auth_token)
self.project = self.render(self.config.project)
def render(self, template: str) -> str:
return self.renderer.render(template)
@ -169,9 +176,8 @@ class ADO:
if document:
self.client.update_work_item(document, item.id, project=self.project)
def create_new(self) -> None:
def render_new(self) -> Tuple[str, List[JsonPatchOperation]]:
task_type = self.render(self.config.type)
document = []
if "System.Tags" not in self.config.ado_fields:
document.append(
@ -187,6 +193,10 @@ class ADO:
document.append(
JsonPatchOperation(op="Add", path="/fields/%s" % field, value=value)
)
return (task_type, document)
def create_new(self) -> None:
task_type, document = self.render_new()
entry = self.client.create_work_item(
document=document, project=self.project, type=task_type

View File

@ -37,34 +37,53 @@ def fail_task(report: Report, error: Exception) -> None:
class Render:
def __init__(self, container: Container, filename: str, report: Report):
def __init__(
self,
container: Container,
filename: str,
report: Report,
*,
task: Optional[Task] = None,
job: Optional[Job] = None,
target_url: Optional[str] = None,
input_url: Optional[str] = None,
report_url: Optional[str] = None,
):
self.report = report
self.container = container
self.filename = filename
task = Task.get(report.job_id, report.task_id)
if not task:
raise ValueError(f"invalid task {report.task_id}")
job = Job.get(report.job_id)
task = Task.get(report.job_id, report.task_id)
if not task:
raise ValueError(f"invalid task {report.task_id}")
if not job:
raise ValueError(f"invalid job {report.job_id}")
job = Job.get(report.job_id)
if not job:
raise ValueError(f"invalid job {report.job_id}")
self.task_config = task.config
self.job_config = job.config
self.env = SandboxedEnvironment()
self.target_url: Optional[str] = None
setup_container = get_setup_container(task.config)
if setup_container:
self.target_url = auth_download_url(
setup_container, self.report.executable.replace("setup/", "", 1)
)
self.target_url = target_url
if not self.target_url:
setup_container = get_setup_container(task.config)
if setup_container:
self.target_url = auth_download_url(
setup_container, self.report.executable.replace("setup/", "", 1)
)
self.report_url = auth_download_url(container, filename)
self.input_url: Optional[str] = None
if self.report.input_blob:
self.input_url = auth_download_url(
self.report.input_blob.container, self.report.input_blob.name
)
if report_url:
self.report_url = report_url
else:
self.report_url = auth_download_url(container, filename)
self.input_url = input_url
if not self.input_url:
if self.report.input_blob:
self.input_url = auth_download_url(
self.report.input_blob.container, self.report.input_blob.name
)
def render(self, template: str) -> str:
return self.env.from_string(template).render(

View File

@ -0,0 +1,32 @@
{
"base_url": "https://dev.azure.com/contoso",
"auth_token": "DO NOT PUT YOUR PAT HERE",
"type": "Bug",
"project": "Contoso",
"unique_fields": [
"Microsoft.VSTS.Build.FoundIn"
],
"comment": "my comment",
"ado_fields": {
"System.AssignedTo": "example@contoso.com",
"System.Tags": "OneFuzz; OneFuzz-Pipeline; example@example.com",
"System.AreaPath": "MY\\AREA Path\\Here",
"System.IterationPath": "MY\\ITERATION",
"Microsoft.VSTS.Scheduling.StoryPoints": "1",
"Microsoft.VSTS.Build.FoundIn": "{{ report.input_sha256 }}",
"System.Title": "[OneFuzz] - {{ report.crash_site }}",
"Microsoft.VSTS.TCM.ReproSteps": "This is the call stack. You may wish to confirm: <ul> {% for item in report.call_stack %} <li> {{ item }} </li> {% endfor %} </ul>"
},
"on_duplicate": {
"comment": "DEDUPED!",
"set_state": {
"Resolved": "Active"
},
"ado_fields": {
"System.IterationPath": "MY\\ITERATION"
},
"increment": [
"Microsoft.VSTS.Scheduling.StoryPoints"
]
}
}

View File

@ -0,0 +1,42 @@
[
{
"op": "Add",
"path": "/fields/System.AssignedTo",
"value": "example@contoso.com"
},
{
"op": "Add",
"path": "/fields/System.Tags",
"value": "OneFuzz; OneFuzz-Pipeline; example@example.com;Onefuzz"
},
{
"op": "Add",
"path": "/fields/System.AreaPath",
"value": "MY\\AREA Path\\Here"
},
{
"op": "Add",
"path": "/fields/System.IterationPath",
"value": "MY\\ITERATION"
},
{
"op": "Add",
"path": "/fields/Microsoft.VSTS.Scheduling.StoryPoints",
"value": "1"
},
{
"op": "Add",
"path": "/fields/Microsoft.VSTS.Build.FoundIn",
"value": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"op": "Add",
"path": "/fields/System.Title",
"value": "[OneFuzz] - callfunc"
},
{
"op": "Add",
"path": "/fields/Microsoft.VSTS.TCM.ReproSteps",
"value": "This is the call stack. You may wish to confirm: <ul> <li> test.exe.exe+0x2 </li> <li> test.exe.exe+0x9 </li> <li> test.exe.exe+0x3 </li> <li> test.exe.exe+0xd </li> <li> test.exe.exe+0x8 </li> <li> test.exe.exe+0x8 </li> <li> test.exe.exe+0x2 </li> </ul>"
}
]

View File

@ -0,0 +1,23 @@
{
"call_stack": [
"test.exe.exe+0x2",
"test.exe.exe+0x9",
"test.exe.exe+0x3",
"test.exe.exe+0xd",
"test.exe.exe+0x8",
"test.exe.exe+0x8",
"test.exe.exe+0x2"
],
"call_stack_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"crash_site": "callfunc",
"crash_type": "customtype",
"executable": "test2.exe",
"input_blob": {
"account": "storageaccount1",
"container": "storagecontainer1",
"name": "%23A_B.exe.exe%2B0x0_a_b_c_0x5b1e7_a_515c01e.tar"
},
"input_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"job_id": "581e0ba6-9757-47e5-a077-dba21e604961",
"task_id": "4a949007-b59f-4a47-8418-8a2c94b4aef1"
}

View File

@ -0,0 +1,86 @@
#!/usr/bin/env python
#
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
import json
import unittest
from pathlib import Path
from unittest.mock import patch
from onefuzztypes.enums import OS, TaskType
from onefuzztypes.models import ADOTemplate, JobConfig, Report, TaskConfig, TaskDetails
from onefuzztypes.primitives import Container
from __app__.onefuzzlib.jobs import Job
from __app__.onefuzzlib.notifications.ado import ADO
from __app__.onefuzzlib.notifications.common import Render
from __app__.onefuzzlib.tasks.main import Task
class TestReportParse(unittest.TestCase):
def setUp(self) -> None:
self.env_patch = patch.dict(
"os.environ", {"ONEFUZZ_INSTANCE_NAME": "contoso-test"}
)
self.env_patch.start()
def tearDown(self) -> None:
self.env_patch.stop()
def test_sample(self) -> None:
expected_path = Path(__file__).parent / "data" / "ado-rendered.json"
with open(expected_path, "r") as handle:
expected_document = json.load(handle)
report_path = Path(__file__).parent / "data" / "crash-report-with-html.json"
with open(report_path, "r") as handle:
report_raw = json.load(handle)
ado_path = Path(__file__).parent / "data" / "ado-config.json"
with open(ado_path, "r") as handle:
ado_raw = json.load(handle)
report = Report.parse_obj(report_raw)
config = ADOTemplate.parse_obj(ado_raw)
container = Container("containername")
filename = "test.json"
job = Job(
config=JobConfig(project="project", name="name", build="build", duration=1)
)
task = Task(
config=TaskConfig(
job_id=job.job_id,
tags={},
containers=[],
task=TaskDetails(type=TaskType.libfuzzer_fuzz, duration=1),
),
job_id=job.job_id,
os=OS.linux,
)
renderer = Render(
container,
filename,
report,
task=task,
job=job,
target_url="https://contoso.com/1",
input_url="https://contoso.com/2",
report_url="https://contoso.com/3",
)
ado = ADO(container, filename, config, report, renderer=renderer)
work_item_type, document = ado.render_new()
self.assertEqual(work_item_type, "Bug")
as_obj = [x.as_dict() for x in document]
self.assertEqual(as_obj, expected_document)
if __name__ == "__main__":
unittest.main()