Skip to content

Commit 000e3ee

Browse files
Misc fixes and test robustness changes
1 parent 928ab5d commit 000e3ee

11 files changed

Lines changed: 1069 additions & 1059 deletions

File tree

frontend/calcusliveserver.py

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from selenium.webdriver.support import expected_conditions as EC
3737
from selenium.webdriver.chrome.options import Options
3838
from selenium.webdriver.common.action_chains import ActionChains
39+
from selenium.webdriver.remote.client_config import ClientConfig
3940

4041
from celery.contrib.testing.worker import start_worker
4142
from celery.contrib.abortable import AbortableAsyncResult
@@ -77,6 +78,7 @@
7778

7879
class CalcusLiveServer(StaticLiveServerTestCase):
7980
host = "0.0.0.0"
81+
REMOTE_DRIVER_TIMEOUT = 60
8082

8183
@classmethod
8284
def _make_driver(cls):
@@ -85,9 +87,13 @@ def _make_driver(cls):
8587
chrome_options.add_argument("--headless")
8688
driver = webdriver.Chrome(options=chrome_options)
8789
else:
90+
selenium_hub = "http://selenium:4444/wd/hub"
8891
driver = webdriver.Remote(
89-
command_executor="http://selenium:4444/wd/hub",
92+
command_executor=selenium_hub,
9093
options=chrome_options,
94+
client_config=ClientConfig(
95+
remote_server_addr=selenium_hub, timeout=cls.REMOTE_DRIVER_TIMEOUT
96+
),
9197
)
9298

9399
driver.set_window_size(ZOOM * 1920, ZOOM * 1080)
@@ -102,6 +108,18 @@ def _restart_driver(cls):
102108
pass
103109
cls.driver = cls._make_driver()
104110

111+
@classmethod
112+
def _restart_celery_worker(cls):
113+
if IS_CLOUD:
114+
return
115+
116+
if hasattr(cls, "celery_worker"):
117+
cls.celery_worker.__exit__(None, None, None)
118+
119+
app.loader.import_module("celery.contrib.testing.tasks")
120+
cls.celery_worker = start_worker(app, perform_ping_check=False)
121+
cls.celery_worker.__enter__()
122+
105123
@classmethod
106124
def setUpClass(cls):
107125
super().setUpClass()
@@ -112,10 +130,7 @@ def setUpClass(cls):
112130
tasks.REMOTE = False
113131

114132
if not IS_CLOUD:
115-
app.loader.import_module("celery.contrib.testing.tasks")
116-
117-
cls.celery_worker = start_worker(app, perform_ping_check=False)
118-
cls.celery_worker.__enter__()
133+
cls._restart_celery_worker()
119134

120135
if os.path.isdir(SCR_DIR):
121136
rmtree(SCR_DIR)
@@ -264,6 +279,9 @@ def setUp(self):
264279
self.current_order_id = None
265280
self.order_ids_before_launch = None
266281

282+
if not IS_CLOUD:
283+
self.__class__._restart_celery_worker()
284+
267285
self.user = User.objects.create_user(
268286
email=self.email,
269287
password=self.password,
@@ -1530,10 +1548,19 @@ def click_latest_calc(self):
15301548
assert self.is_on_page_calculations()
15311549
assert self.get_number_calc_orders() > 0
15321550

1533-
calculations = self.get_calc_orders()
1534-
self.current_order_id = calculations[0].get_attribute("id")
1551+
target = self._get_target_calc_order()
1552+
if target is None:
1553+
target_order_id = self._get_target_order_id()
1554+
if target_order_id is not None:
1555+
self.current_order_id = f"order_{target_order_id}"
1556+
self.order_ids_before_launch = None
1557+
self.driver.get(f"{self.live_server_url}/link_order/{target_order_id}")
1558+
self.wait_for_ajax()
1559+
return
1560+
target = self.get_calc_orders()[0]
1561+
self.current_order_id = target.get_attribute("id")
15351562
self.order_ids_before_launch = None
1536-
link = calculations[0].find_element(By.CSS_SELECTOR, "a[href^='/link_order/']")
1563+
link = target.find_element(By.CSS_SELECTOR, "a[href^='/link_order/']")
15371564
self.driver.get(link.get_attribute("href"))
15381565
self.wait_for_ajax()
15391566

@@ -1551,32 +1578,58 @@ def details_latest_order(self):
15511578
assert self.is_on_page_calculations()
15521579
assert self.get_number_calc_orders() > 0
15531580

1554-
calculations = self.get_calc_orders()
1555-
self.current_order_id = calculations[0].get_attribute("id")
1581+
target = self._get_target_calc_order()
1582+
if target is None:
1583+
target_order_id = self._get_target_order_id()
1584+
if target_order_id is not None:
1585+
self.current_order_id = f"order_{target_order_id}"
1586+
self.order_ids_before_launch = None
1587+
self.driver.get(
1588+
f"{self.live_server_url}/calculationorder/{target_order_id}"
1589+
)
1590+
self.wait_for_ajax()
1591+
return
1592+
target = self.get_calc_orders()[0]
1593+
self.current_order_id = target.get_attribute("id")
15561594
self.order_ids_before_launch = None
15571595

1558-
icon = calculations[0].find_element(By.CLASS_NAME, "fa-list")
1596+
icon = target.find_element(By.CLASS_NAME, "fa-list")
15591597
link = icon.find_element(By.XPATH, "./ancestor::a[1]")
15601598
self.driver.get(link.get_attribute("href"))
15611599
self.wait_for_ajax()
15621600

1601+
def _get_target_order_id(self):
1602+
if self.current_order_id is not None:
1603+
return self.current_order_id.removeprefix("order_")
1604+
1605+
if self.order_ids_before_launch is None:
1606+
return None
1607+
1608+
close_old_connections()
1609+
current_ids = {
1610+
f"order_{order_id}"
1611+
for order_id in CalculationOrder.objects.values_list("id", flat=True)
1612+
}
1613+
new_ids = current_ids - self.order_ids_before_launch
1614+
if not new_ids:
1615+
return None
1616+
1617+
target_id = sorted(new_ids)[-1]
1618+
self.current_order_id = target_id
1619+
self.order_ids_before_launch = None
1620+
return target_id.removeprefix("order_")
1621+
15631622
def _get_target_calc_order(self):
15641623
calculations = self.get_calc_orders()
1565-
if self.current_order_id is None and self.order_ids_before_launch is not None:
1566-
for calc in calculations:
1567-
calc_id = calc.get_attribute("id")
1568-
if calc_id not in self.order_ids_before_launch:
1569-
self.current_order_id = calc_id
1570-
self.order_ids_before_launch = None
1571-
return calc
1572-
return None
1573-
if self.current_order_id is None:
1624+
target_order_id = self._get_target_order_id()
1625+
if target_order_id is None:
15741626
return calculations[0]
15751627

1628+
target_dom_id = f"order_{target_order_id}"
15761629
for calc in calculations:
1577-
if calc.get_attribute("id") == self.current_order_id:
1630+
if calc.get_attribute("id") == target_dom_id:
15781631
return calc
1579-
return calculations[0]
1632+
return None
15801633

15811634
def _refresh_calculations_page(self):
15821635
self.driver.refresh()
@@ -1713,6 +1766,18 @@ def wait_latest_calc_done(self, timeout):
17131766
self._refresh_calculations_page()
17141767
return
17151768

1769+
target_order_id = self._get_target_order_id()
1770+
if target_order_id is not None:
1771+
close_old_connections()
1772+
backend_status = (
1773+
CalculationOrder.objects.filter(id=target_order_id)
1774+
.values_list("cached_status", flat=True)
1775+
.first()
1776+
)
1777+
if backend_status in [2, 3]:
1778+
self._refresh_calculations_page()
1779+
return
1780+
17161781
time.sleep(0.5)
17171782
self._refresh_calculations_page()
17181783
raise Exception("Calculation did not finish")

frontend/models.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,25 @@ def bill_time(self, time):
238238

239239
return user
240240

241+
@classmethod
242+
def from_db(cls, db, field_names, values):
243+
instance = super().from_db(db, field_names, values)
244+
if "unseen_calculations" in field_names:
245+
instance._loaded_unseen_calculations = instance.unseen_calculations
246+
else:
247+
instance._loaded_unseen_calculations = None
248+
return instance
249+
241250
def save(self, *args, **kwargs):
242251
update_fields = kwargs.get("update_fields")
243-
should_preserve_unseen = (
244-
self.pk is not None
245-
and update_fields is not None
246-
and "unseen_calculations" not in update_fields
252+
should_preserve_unseen = self.pk is not None and (
253+
(update_fields is not None and "unseen_calculations" not in update_fields)
254+
or (
255+
update_fields is None
256+
and hasattr(self, "_loaded_unseen_calculations")
257+
and self._loaded_unseen_calculations is not None
258+
and self.unseen_calculations == self._loaded_unseen_calculations
259+
)
247260
)
248261
if should_preserve_unseen:
249262
current_unseen = (
@@ -255,6 +268,7 @@ def save(self, *args, **kwargs):
255268
self.unseen_calculations = current_unseen
256269

257270
super().save(*args, **kwargs)
271+
self._loaded_unseen_calculations = self.unseen_calculations
258272

259273
@property
260274
def is_PI(self):
@@ -1401,7 +1415,7 @@ def _get_label(self):
14011415
def molecule_name(self):
14021416
if self._molecule_name == "":
14031417
self._molecule_name = self._get_molecule_name()
1404-
self.save()
1418+
self.save(update_fields=["_molecule_name"])
14051419
return self._molecule_name
14061420

14071421
@property
@@ -1411,7 +1425,7 @@ def step_name(self):
14111425
self._step_name = "Unknown"
14121426
else:
14131427
self._step_name = self.step.name
1414-
self.save()
1428+
self.save(update_fields=["_step_name"])
14151429
return self._step_name
14161430

14171431
@property
@@ -1421,7 +1435,7 @@ def project_name(self):
14211435
self._project_name = "Unknown"
14221436
else:
14231437
self._project_name = self.project.name
1424-
self.save()
1438+
self.save(update_fields=["_project_name"])
14251439
return self._project_name
14261440

14271441
def _get_molecule_name(self):

0 commit comments

Comments
 (0)