Skip to content

Commit

Permalink
feature(graphs-views): show predefined list of graphs
Browse files Browse the repository at this point in the history
Users are allowed to create 'Graph Views' which can store specific
graphs. Created Graph Views are visible in test's graph window and can
be selected for quick look on saved graphs list. This way saving time
for playing with filters.

Graph Views may have a name and description.

closes: scylladb#554
  • Loading branch information
soyacz committed Jan 3, 2025
1 parent b8e19dd commit 253f2bd
Show file tree
Hide file tree
Showing 6 changed files with 494 additions and 83 deletions.
34 changes: 33 additions & 1 deletion argus/backend/controller/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,42 @@ def test_results():
return Response(status=200 if exists else 404)

graphs, ticks, releases_filters = service.get_test_graphs(test_id=UUID(test_id), start_date=start_date, end_date=end_date)
graph_views = service.get_argus_graph_views(test_id=UUID(test_id))

return {
"status": "ok",
"response": {"graphs": graphs, "ticks": ticks, "releases_filters": releases_filters}
"response": {"graphs": graphs, "ticks": ticks, "releases_filters": releases_filters, "graph_views": graph_views}
}

@bp.route("/create-graph-view", methods=["POST"])
@api_login_required
def create_graph_view():
payload = get_payload(request)
service = ResultsService()
test_id = payload["testId"]
name = payload["name"]
description = payload["description"]
graph_view = service.create_argus_graph_view(test_id=UUID(test_id), name=name, description=description)
return {
"status": "ok",
"response": graph_view
}

@bp.route("/update-graph-view", methods=["POST"])
@api_login_required
def update_graph_view():
payload = get_payload(request)
service = ResultsService()
test_id = payload["testId"]
id = payload["id"]
name = payload["name"]
description = payload["description"]
graphs = payload["graphs"]
graph_view = service.update_argus_graph_view(test_id=UUID(test_id), view_id=UUID(id), name=name, description=description,
graphs=graphs)
return {
"status": "ok",
"response": graph_view
}

@bp.route("/test_run/comment/get", methods=["GET"]) # TODO: remove
Expand Down
8 changes: 8 additions & 0 deletions argus/backend/models/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,11 @@ class ArgusBestResultData(Model):
key = columns.Ascii(primary_key=True) # represents pair column:row
value = columns.Double()
run_id = columns.UUID()

class ArgusGraphView(Model):
__table_name__ = "graph_view_v1"
test_id = columns.UUID(partition_key=True)
id = columns.UUID(primary_key=True)
name = columns.Text()
description = columns.Text()
graphs = columns.Map(key_type=columns.Text(), value_type=columns.Ascii()) # key: graph name, value: graph properties (e.g. size)
3 changes: 2 additions & 1 deletion argus/backend/models/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from cassandra.util import uuid_from_time, unix_time_from_uuid1 # pylint: disable=no-name-in-module

from argus.backend.models.plan import ArgusReleasePlan
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ArgusBestResultData
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ArgusBestResultData, ArgusGraphView
from argus.backend.models.view_widgets import WidgetHighlights, WidgetComment


Expand Down Expand Up @@ -390,6 +390,7 @@ class WebFileStorage(Model):
ArgusReleasePlan,
WidgetHighlights,
WidgetComment,
ArgusGraphView,
]

USED_TYPES: list[UserType] = [
Expand Down
39 changes: 37 additions & 2 deletions argus/backend/service/results_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from datetime import datetime, timezone
from functools import partial, cache
from typing import List, Dict, Any
from uuid import UUID
from uuid import UUID, uuid4

from dataclasses import dataclass
from argus.backend.db import ScyllaCluster
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ArgusBestResultData, ColumnMetadata
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ArgusBestResultData, ColumnMetadata, ArgusGraphView
from argus.backend.plugins.sct.udt import PackageVersion
from argus.backend.service.testrun import TestRunService

Expand Down Expand Up @@ -622,3 +622,38 @@ def get_tests_by_version(self, sut_package_name: str, test_ids: list[UUID]) -> d
'versions': {version: dict(tests) for version, tests in result.items()},
'test_info': test_info
}

def create_argus_graph_view(self, test_id: UUID, name: str, description: str) -> ArgusGraphView:
view_id = uuid4()
graph_view = ArgusGraphView(test_id=test_id, id=view_id)
graph_view.name = name
graph_view.description = description
graph_view.save()
return graph_view

def update_argus_graph_view(self, test_id: UUID, view_id: UUID, name: str, description: str,
graphs: dict[str, str]) -> ArgusGraphView:
try:
graph_view = ArgusGraphView.get(test_id=test_id, id=view_id)
except ArgusGraphView.DoesNotExist:
raise ValueError(f"GraphView with id {view_id} does not exist for test {test_id}")

existing_keys = set(graph_view.graphs.keys())
new_keys = set(graphs.keys())
keys_to_remove = existing_keys - new_keys

for key in keys_to_remove:
ArgusGraphView.objects(test_id=test_id, id=view_id).update(graphs={key: None})

if graphs:
ArgusGraphView.objects(test_id=test_id, id=view_id).update(graphs=graphs)

ArgusGraphView.objects(test_id=test_id, id=view_id).update(
name=name,
description=description
)

return ArgusGraphView.get(test_id=test_id, id=view_id)

def get_argus_graph_views(self, test_id: UUID) -> list[ArgusGraphView]:
return list(ArgusGraphView.objects(test_id=test_id))
31 changes: 30 additions & 1 deletion argus/backend/tests/results_service/test_results_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from uuid import uuid4

import pytest
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ColumnMetadata
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData, ColumnMetadata, ArgusGraphView
from argus.backend.plugins.sct.testrun import SCTTestRun
from argus.backend.plugins.sct.udt import PackageVersion
from argus.backend.service.results_service import ResultsService
Expand Down Expand Up @@ -170,3 +170,32 @@ def test_get_tests_by_version_groups_runs_correctly(argus_db):
'started_by': None,
'status': 'created'}}}}}
assert result == expected_result


def test_create_update_argus_graph_view_should_create() -> None:
service = ResultsService()
test_id = uuid4()
service.create_argus_graph_view(test_id, "MyView", "MyDescription")
result = service.get_argus_graph_views(test_id)[0]
assert result is not None
assert result.name == "MyView"
assert result.description == "MyDescription"
assert result.graphs == {}

def test_create_update_argus_graph_view_should_update() -> None:
service = ResultsService()
test_id = uuid4()
graph_view = service.create_argus_graph_view(test_id, "OldName", "OldDesc")
service.update_argus_graph_view(test_id, graph_view.id, "NewName", "NewDesc", {"graph2": "new_data"})
updated = service.get_argus_graph_views(test_id)[0]
assert updated.name == "NewName"
assert updated.description == "NewDesc"
assert updated.graphs == {"graph2": "new_data"}

def test_get_argus_graph_views_should_return_list() -> None:
service = ResultsService()
test_id = uuid4()
service.create_argus_graph_view(test_id, "View1", "Desc1")
service.create_argus_graph_view(test_id, "View2", "Desc2")
views = service.get_argus_graph_views(test_id)
assert len(views) == 2
Loading

0 comments on commit 253f2bd

Please sign in to comment.