1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00

fix(instances): the VM page reloads only when the VM state changes

The VM page polls the VM state every 5 s and reloads when it differs
from the state the page was rendered with. Since the polling moved to
pollWhileVisible, that state was kept in a top-level "var status",
which is not a page variable but the browser's window.status. Where the
browser does not keep a value there, the poll compared the answer with
"" and reloaded the page every 5 s, back to its first tab.

The variable is now vm_status. A Node test runs the page's script with
a window.status that keeps nothing.
This commit is contained in:
catborise 2026-10-06 12:27:45 +03:00
parent c2fea2aa39
commit 490b337453
2 changed files with 34 additions and 2 deletions

View file

@ -652,11 +652,12 @@
</script>
<script>
backgroundJobRunning = false;
var status = {{ instance.status|lower }};
// not "status": that is window.status, which the browser may not keep
var vm_status = {{ instance.status|lower }};
var status_poll = pollWhileVisible(5000, function () {
return $.getJSON("{% url 'instances:status' instance.id %}");
}, function get_status(data) {
if (data['status'] != status && !backgroundJobRunning) {
if (data['status'] != vm_status && !backgroundJobRunning) {
window.location.reload()
}
});

View file

@ -1,6 +1,8 @@
"""Pages poll the server through static/js/poll.js: one request at a time,
none while the page is hidden. Its behaviour is checked with Node."""
import json
import re
import shutil
import subprocess
import unittest
@ -29,3 +31,32 @@ class PollTestCase(unittest.TestCase):
source = (BASE / template).read_text()
self.assertNotIn("setInterval", source)
self.assertIn("pollWhileVisible(", source)
@unittest.skipUnless(shutil.which("node"), "node is not installed")
def test_the_vm_page_reloads_only_when_the_state_changes(self):
# "status" is a property of the browser's window: a page variable of
# that name holds what the browser makes of it (a string, or nothing)
source = (BASE / "instances/templates/instance.html").read_text()
script = re.search(r"<script>\s*(backgroundJobRunning = false;.*?)</script>", source, re.S).group(1)
script = script.replace("{{ instance.status|lower }}", "1").replace(
"{% url 'instances:status' instance.id %}", "/instances/1/status/"
)
js = """
const vm = require("vm");
const results = {};
for (const answer of [1, 5]) {
let reloads = 0;
const page = {
pollWhileVisible: (interval, request, onData) => { onData({status: answer}); return {stop() {}}; },
$: () => ({submit() {}}),
};
page.window = {location: {reload: () => reloads++}};
Object.defineProperty(page, "status", {get: () => "", set: () => {}});
vm.runInNewContext(SCRIPT, vm.createContext(page));
results[answer] = reloads;
}
console.log(JSON.stringify(results));
""".replace("SCRIPT", json.dumps(script))
out = subprocess.run(["node", "-e", js], capture_output=True, text=True, timeout=30)
self.assertEqual(out.returncode, 0, out.stderr)
self.assertEqual(json.loads(out.stdout), {"1": 0, "5": 1})