Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reporting environment issues #213

Merged
merged 12 commits into from
Sep 18, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Add EnvironmentIssue table

Revision ID: 505b96fd7731
Revises: ba6550a03bc8
Create Date: 2024-09-16 10:52:25.226261+00:00

"""
import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "505b96fd7731"
down_revision = "ba6550a03bc8"
branch_labels = None
depends_on = None


def upgrade() -> None:
op.create_table(
"environment_issue",
sa.Column("environment_name", sa.String(), nullable=False),
sa.Column("url", sa.String(), nullable=False),
sa.Column("description", sa.String(), nullable=False),
sa.Column("is_confirmed", sa.Boolean(), nullable=False),
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id", name=op.f("environment_issue_pkey")),
)


def downgrade() -> None:
op.drop_table("environment_issue")
43 changes: 36 additions & 7 deletions backend/scripts/seed_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from sqlalchemy import select
from sqlalchemy.orm import Session

from test_observer.controllers.test_cases.models import ReportedIssueRequest
from test_observer.controllers.environments import models as environment_issues_models
from test_observer.controllers.test_cases import models as test_issues_models
from test_observer.controllers.test_executions.models import (
C3TestResult,
C3TestResultStatus,
Expand All @@ -28,6 +29,7 @@
END_TEST_EXECUTION_URL = f"{BASE_URL}/test-executions/end-test"
RERUN_TEST_EXECUTION_URL = f"{BASE_URL}/test-executions/reruns"
TEST_CASE_ISSUE_URL = f"{BASE_URL}/test-cases/reported-issues"
ENVIRONMENT_ISSUE_URL = f"{BASE_URL}/environments/reported-issues"

START_TEST_EXECUTION_REQUESTS = [
StartTestExecutionRequest(
Expand Down Expand Up @@ -288,23 +290,44 @@
]

TEST_CASE_ISSUE_REQUESTS = [
ReportedIssueRequest(
test_issues_models.ReportedIssueRequest(
omar-selo marked this conversation as resolved.
Show resolved Hide resolved
template_id=END_TEST_EXECUTION_REQUESTS[0].test_results[2].template_id, # type: ignore
url=HttpUrl("http://bug1.link"),
url=HttpUrl("https://github.com"),
description="known issue 1",
),
ReportedIssueRequest(
test_issues_models.ReportedIssueRequest(
case_name=END_TEST_EXECUTION_REQUESTS[0].test_results[0].name,
url=HttpUrl("http://bug2.link"),
url=HttpUrl("https://warthogs.atlassian.net"),
description="known issue 2",
),
ReportedIssueRequest(
test_issues_models.ReportedIssueRequest(
case_name=END_TEST_EXECUTION_REQUESTS[0].test_results[1].name,
url=HttpUrl("http://bug3.link"),
url=HttpUrl("https://bugs.launchpad.net"),
description="known issue 3",
),
]

ENVIRONMENT_ISSUE_REQUESTS = [
environment_issues_models.ReportedIssueRequest(
environment_name=START_TEST_EXECUTION_REQUESTS[0].environment,
url=HttpUrl("https://github.com"),
description="known issue 1",
is_confirmed=True,
),
environment_issues_models.ReportedIssueRequest(
environment_name=START_TEST_EXECUTION_REQUESTS[1].environment,
url=HttpUrl("https://warthogs.atlassian.net"),
description="known issue 2",
is_confirmed=False,
),
environment_issues_models.ReportedIssueRequest(
environment_name=START_TEST_EXECUTION_REQUESTS[2].environment,
url=HttpUrl("https://bugs.launchpad.net"),
description="known issue 3",
is_confirmed=True,
),
]


def seed_data(client: TestClient | requests.Session, session: Session | None = None):
session = session or SessionLocal()
Expand Down Expand Up @@ -334,6 +357,12 @@ def seed_data(client: TestClient | requests.Session, session: Session | None = N
TEST_CASE_ISSUE_URL, json=case_issue_request.model_dump(mode="json")
).raise_for_status()

for environment_issue_request in ENVIRONMENT_ISSUE_REQUESTS:
client.post(
ENVIRONMENT_ISSUE_URL,
json=environment_issue_request.model_dump(mode="json"),
).raise_for_status()

_rerun_some_test_executions(client, test_executions)

_add_bugurl_and_duedate(session)
Expand Down
2 changes: 2 additions & 0 deletions backend/test_observer/common/constants.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
PREVIOUS_TEST_RESULT_COUNT = 10

VALID_ISSUE_HOSTS = {"github.com", "warthogs.atlassian.net", "bugs.launchpad.net"}
6 changes: 6 additions & 0 deletions backend/test_observer/controllers/environments/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from fastapi import APIRouter

from . import reported_issues

router = APIRouter(tags=["environments"])
router.include_router(reported_issues.router)
31 changes: 31 additions & 0 deletions backend/test_observer/controllers/environments/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from datetime import datetime

from pydantic import BaseModel, HttpUrl, field_validator

from test_observer.common.constants import VALID_ISSUE_HOSTS


class ReportedIssueRequest(BaseModel):
environment_name: str
description: str
url: HttpUrl
is_confirmed: bool

@field_validator("url")
@classmethod
def name_must_contain_space(
cls: type["ReportedIssueRequest"], url: HttpUrl
) -> HttpUrl:
if url.host not in VALID_ISSUE_HOSTS:
raise ValueError(f"Issue url must belong to one of {VALID_ISSUE_HOSTS}")
return url


class ReportedIssueResponse(BaseModel):
id: int
environment_name: str
description: str
url: HttpUrl
is_confirmed: bool
created_at: datetime
updated_at: datetime
48 changes: 48 additions & 0 deletions backend/test_observer/controllers/environments/reported_issues.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from fastapi import APIRouter, Depends
from sqlalchemy import select
from sqlalchemy.orm import Session

from test_observer.data_access.models import EnvironmentIssue
from test_observer.data_access.setup import get_db

from .models import ReportedIssueRequest, ReportedIssueResponse

router = APIRouter()

endpoint = "/reported-issues"


@router.get(endpoint, response_model=list[ReportedIssueResponse])
def get_reported_issues(db: Session = Depends(get_db)):
return db.execute(select(EnvironmentIssue)).scalars()


@router.post(endpoint, response_model=ReportedIssueResponse)
def create_reported_issue(request: ReportedIssueRequest, db: Session = Depends(get_db)):
issue = EnvironmentIssue(
environment_name=request.environment_name,
url=request.url,
description=request.description,
is_confirmed=request.is_confirmed,
)
db.add(issue)
db.commit()

return issue


@router.put(endpoint + "/{issue_id}", response_model=ReportedIssueResponse)
def update_reported_issue(
issue_id: int, request: ReportedIssueRequest, db: Session = Depends(get_db)
):
issue = db.get(EnvironmentIssue, issue_id)
for field in request.model_fields:
setattr(issue, field, getattr(request, field))
db.commit()
return issue


@router.delete(endpoint + "/{issue_id}")
def delete_reported_issue(issue_id: int, db: Session = Depends(get_db)):
db.delete(db.get(EnvironmentIssue, issue_id))
db.commit()
3 changes: 2 additions & 1 deletion backend/test_observer/controllers/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

from test_observer.data_access.setup import get_db

from . import test_cases, test_executions
from . import environments, test_cases, test_executions
from .application import version
from .artefacts import artefacts
from .reports import reports
Expand All @@ -34,6 +34,7 @@
router.include_router(artefacts.router, prefix="/v1/artefacts")
router.include_router(reports.router, prefix="/v1/reports")
router.include_router(test_cases.router, prefix="/v1/test-cases")
router.include_router(environments.router, prefix="/v1/environments")


@router.get("/")
Expand Down
14 changes: 13 additions & 1 deletion backend/test_observer/controllers/test_cases/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from datetime import datetime

from pydantic import BaseModel, HttpUrl, model_validator
from pydantic import BaseModel, HttpUrl, field_validator, model_validator

from test_observer.common.constants import VALID_ISSUE_HOSTS


class ReportedIssueRequest(BaseModel):
Expand All @@ -13,8 +15,18 @@ class ReportedIssueRequest(BaseModel):
def check_a_or_b(self):
if not self.case_name and not self.template_id:
raise ValueError("Either case_name or template_id is required")

return self

@field_validator("url")
@classmethod
def name_must_contain_space(
omar-selo marked this conversation as resolved.
Show resolved Hide resolved
cls: type["ReportedIssueRequest"], url: HttpUrl
) -> HttpUrl:
if url.host not in VALID_ISSUE_HOSTS:
raise ValueError(f"Issue url must belong to one of {VALID_ISSUE_HOSTS}")
return url


class ReportedIssueResponse(BaseModel):
id: int
Expand Down
22 changes: 22 additions & 0 deletions backend/test_observer/data_access/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,28 @@ def __repr__(self) -> str:
return data_model_repr(
self,
"template_id",
"case_name",
"url",
"description",
)


class EnvironmentIssue(Base):
"""
A table to store issues reported on certain environments
"""

__tablename__ = "environment_issue"

environment_name: Mapped[str]
url: Mapped[str]
description: Mapped[str]
is_confirmed: Mapped[bool]

def __repr__(self) -> str:
return data_model_repr(
self,
"environment_name",
"url",
"description",
)
8 changes: 8 additions & 0 deletions backend/tests/asserts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from httpx import Response


def assert_fails_validation(response: Response, field: str, type: str) -> None:
assert response.status_code == 422
problem = response.json()["detail"][0]
assert problem["type"] == type
assert problem["loc"] == ["body", field]
Loading
Loading