mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
The search box filtered only the 100 rows on screen, in the browser: an older row seemed not to exist. The page now searches on the server, in every row's user, host, VM, VM UUID, message and IP, as plain text, and can show the failed rows only; its pages keep the search. Failed rows are marked red, dates carry the year and the time zone, and a VM's rows link to the VM while it is in the panel. Excel downloads the rows the search chooses, all pages of them, with the VM report's workbook (text stays text).
87 lines
4.5 KiB
Python
87 lines
4.5 KiB
Python
"""The Logs page searches every row on the server, can show the failed ones
|
|
only, says the year and time zone, links a VM's rows to the VM, and downloads
|
|
what it shows as an Excel workbook."""
|
|
|
|
from io import BytesIO
|
|
|
|
from computes.models import Compute
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase, override_settings
|
|
from django.urls import reverse
|
|
from instances.models import Instance
|
|
from logs.models import Logs
|
|
from lxml import html
|
|
from openpyxl import load_workbook
|
|
|
|
UUID = "11111111-2222-3333-4444-555555555555"
|
|
|
|
|
|
@override_settings(TIME_ZONE="UTC")
|
|
class LogsPageTests(TestCase):
|
|
def setUp(self):
|
|
self.admin = get_user_model().objects.create_superuser("lg-admin", "lg@example.com", "pw")
|
|
self.client.force_login(self.admin)
|
|
Logs.objects.all().delete()
|
|
# the row to find is the oldest: past the first page
|
|
Logs.objects.create(user="alice", host="host1", instance="web", instance_uuid=UUID,
|
|
message="VM web: delete", success=False, ip="192.0.2.7")
|
|
Logs.objects.bulk_create(Logs(user="bob", instance="db", message=f"VM db: power on {n}", success=True)
|
|
for n in range(150))
|
|
compute = Compute.objects.create(name="host1", hostname="192.0.2.1", login="u", password="p", type=1)
|
|
self.vm = Instance.objects.create(compute=compute, name="web", uuid=UUID)
|
|
|
|
def page(self, **query):
|
|
return html.fromstring(self.client.get(reverse("admin:logs"), query).content)
|
|
|
|
def rows(self, page):
|
|
return [[" ".join(td.text_content().split()) for td in tr.xpath("td")] for tr in page.xpath("//tbody/tr")]
|
|
|
|
def test_a_search_finds_a_row_on_any_page(self):
|
|
for query in ("alice", "WEB: DELETE", "192.0.2.7", "host1"):
|
|
with self.subTest(query=query):
|
|
rows = self.rows(self.page(q=query))
|
|
self.assertEqual([row[2] for row in rows], ["alice"])
|
|
|
|
def test_a_search_is_text_not_a_pattern(self):
|
|
Logs.objects.create(user="carol", instance="", message="disk (vda) [full]", success=True)
|
|
self.assertEqual([row[2] for row in self.rows(self.page(q="(vda) ["))], ["carol"])
|
|
|
|
def test_the_failed_rows_only_and_marked(self):
|
|
page = self.page(failed="1")
|
|
self.assertEqual([row[2] for row in self.rows(page)], ["alice"])
|
|
self.assertIn("table-danger", page.xpath("//tbody/tr")[0].get("class"))
|
|
|
|
def test_the_pages_keep_the_search(self):
|
|
page = self.page(q="bob")
|
|
self.assertTrue(page.xpath("//a[contains(@href, 'page=2') and contains(@href, 'q=bob')]"))
|
|
|
|
def test_dates_have_the_year_and_the_time_zone(self):
|
|
page = self.page(q="alice")
|
|
self.assertIn("Date (UTC)", [" ".join(th.text_content().split()) for th in page.xpath("//thead//th")])
|
|
log = Logs.objects.get(user="alice")
|
|
self.assertEqual(self.rows(page)[0][1], log.date.strftime("%Y-%m-%d %H:%M:%S"))
|
|
|
|
def test_a_vm_row_links_the_vm_while_it_is_there(self):
|
|
page = self.page(q="alice")
|
|
self.assertEqual(page.xpath("//tbody/tr/td/a/@href"), [reverse("instances:instance", args=[self.vm.pk])])
|
|
self.vm.delete()
|
|
self.assertEqual(self.page(q="alice").xpath("//tbody/tr/td/a"), [])
|
|
|
|
def test_the_rows_shown_download_as_a_workbook(self):
|
|
Logs.objects.create(user="mallory", instance="", message="=HYPERLINK(1)", success=False)
|
|
response = self.client.get(reverse("admin:logs_export"), {"failed": "1"})
|
|
self.assertEqual(response["Content-Type"], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
self.assertIn("attachment", response["Content-Disposition"])
|
|
sheet = load_workbook(BytesIO(response.content)).active
|
|
values = list(sheet.values)
|
|
self.assertEqual(values[0], ("Date (UTC)", "User", "Host", "VM", "VM UUID", "Message", "Result", "IP"))
|
|
self.assertEqual([row[1] for row in values[1:]], ["mallory", "alice"])
|
|
# a message starting with = stays text
|
|
self.assertEqual(sheet.cell(row=2, column=6).data_type, "s")
|
|
page = self.page(q="alice", failed="1")
|
|
self.assertEqual(page.xpath("//a[contains(@href, 'export')]/@href"),
|
|
[reverse("admin:logs_export") + "?q=alice&failed=1"])
|
|
|
|
def test_only_an_administrator_downloads(self):
|
|
self.client.force_login(get_user_model().objects.create_user("lg-user", password="pw"))
|
|
self.assertEqual(self.client.get(reverse("admin:logs_export")).status_code, 403)
|