Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion tcms/rpc/api/testcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from datetime import timedelta

from django.contrib.auth import get_user_model
from django.db.models import OuterRef, Subquery
from django.db.models.functions import Coalesce
from django.forms import EmailField, ValidationError
from django.forms.models import model_to_dict
Expand Down Expand Up @@ -271,12 +272,18 @@ def filter(query=None): # pylint: disable=redefined-builtin
qs = (
TestCase.objects.annotate(
expected_duration=Coalesce("setup_duration", timedelta(0))
+ Coalesce("testing_duration", timedelta(0))
+ Coalesce("testing_duration", timedelta(0)),
last_modified=Subquery(
TestCase.history.model.objects.filter(id=OuterRef("pk"))
.order_by("-history_date")
.values("history_date")[:1]
),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a no-go!

A subquery will essentially make multiple extra queries which will have disastrous effects on performance. On a production dataset with 1684 test cases, which have 2806 historical record between all of them this results in a 2x worse performance!

We've got Kiwi TCMS installations with thousands of test cases where this query will kill the entire application.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try this instead (change what's the model we query and how we find what data to return):

  1. Add
test_case_ids = TestCase.objects.filter(**query).values("id")
  1. Replace TestCase.objects -> HistoricalTestCase.objects
  2. The filter statement becomes .filter(id__in=test_case_ids)
  3. Add history_date in the .values() argument list
  4. Change the order/disctinct clause to
    .order_by("id", "-history_date")
    .distinct("id")

Which essentially means: get me the last available record of each test case which matches the query filter passed to this call and has not been removed.

Then display the "history_date" column with the title "Last modified".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^^ NOTE: the proposed approach above results in 1 extra query to fetch the relevant IDs.

)
.filter(**query)
.values(
"id",
"create_date",
"last_modified",
"is_automated",
"script",
"arguments",
Expand Down
12 changes: 10 additions & 2 deletions tcms/rpc/api/testplan.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

from django.db.models import Count
from django.db.models import Count, OuterRef, Subquery
from django.forms.models import model_to_dict
from modernrpc.core import REQUEST_KEY, rpc_method

Expand Down Expand Up @@ -88,12 +88,20 @@ def filter(query=None): # pylint: disable=redefined-builtin
query = {}

return list(
TestPlan.objects.filter(**query)
TestPlan.objects.annotate(
last_modified=Subquery(
TestPlan.history.model.objects.filter(id=OuterRef("pk"))
.order_by("-history_date")
.values("history_date")[:1]
),
)
.filter(**query)
.values(
"id",
"name",
"text",
"create_date",
"last_modified",
"is_active",
"extra_link",
"product_version",
Expand Down
1 change: 1 addition & 0 deletions tcms/testcases/static/testcases/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export function pageTestcasesSearchReadyHandler () {
}
},
{ data: 'create_date' },
{ data: 'last_modified' },
{ data: 'category__name' },
{ data: 'component_names' },
{ data: 'priority__value' },
Expand Down
5 changes: 5 additions & 0 deletions tcms/testcases/templates/testcases/get.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ <h2 class="card-pf-title kiwi-text-align-left">
<span class="fa fa-calendar"></span>{{ object.create_date }}
</h2>

<h2 class="card-pf-title kiwi-text-align-left">
<span class="fa fa-pencil"></span>{% trans 'Last modified' %}:
{{ last_modified }}
</h2>

<h2 class="card-pf-title kiwi-text-align-left">
<span class="fa fa-clock-o"></span>{% trans 'Setup duration' %}:
{{ object.setup_duration|default:"-" }}
Expand Down
1 change: 1 addition & 0 deletions tcms/testcases/templates/testcases/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
<th>{% trans "ID" %}</th>
<th>{% trans "Summary" %}</th>
<th>{% trans "Created on" %}</th>
<th>{% trans "Last modified" %}</th>
<th>{% trans "Category" %}</th>
<th>{% trans "Component" %}</th>
<th>{% trans "Priority" %}</th>
Expand Down
5 changes: 5 additions & 0 deletions tcms/testcases/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ def get_context_data(self, **kwargs):
context["executions"] = self.object.executions.select_related(
"run", "tested_by", "assignee", "case", "status"
).order_by("run__plan", "run")
context["last_modified"] = (
self.object.history.latest().history_date
if self.object.history.exists()
else self.object.create_date
)
context["OBJECT_MENU_ITEMS"] = [
(
"...",
Expand Down
1 change: 1 addition & 0 deletions tcms/testplans/static/testplans/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export function pageTestplansSearchReadyHandler () {
}
},
{ data: 'create_date' },
{ data: 'last_modified' },
{ data: 'product__name' },
{ data: 'product_version__value' },
{ data: 'type__name' },
Expand Down
5 changes: 5 additions & 0 deletions tcms/testplans/templates/testplans/get.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ <h2 class="card-pf-title kiwi-text-align-left">
<span class="fa fa-calendar"></span>{{ object.create_date }}
</h2>

<h2 class="card-pf-title kiwi-text-align-left">
<span class="fa fa-pencil"></span>{% trans 'Last modified' %}:
{{ last_modified }}
</h2>

<h2 class="card-pf-title kiwi-text-align-left">
<span id="product_pk"
class="fa fa-shopping-cart"></span>{% trans 'Product' %}:
Expand Down
1 change: 1 addition & 0 deletions tcms/testplans/templates/testplans/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
<th>{% trans "ID" %}</th>
<th>{% trans "Test plan" %}</th>
<th>{% trans "Created on" %}</th>
<th>{% trans "Last modified" %}</th>
<th>{% trans "Product" %}</th>
<th>{% trans "Version" %}</th>
<th>{% trans "Type" %}</th>
Expand Down
5 changes: 5 additions & 0 deletions tcms/testplans/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ def get_context_data(self, **kwargs):
context["test_runs"] = TestRun.objects.filter(
plan_id=self.object.pk, stop_date__isnull=True
).order_by("-id")[:5]
context["last_modified"] = (
self.object.history.latest().history_date
if self.object.history.exists()
else self.object.create_date
)
context["OBJECT_MENU_ITEMS"] = [
(
"...",
Expand Down