diff --git a/backend/druks/browser/sessions.py b/backend/druks/browser/sessions.py index e244b656..a0a08142 100644 --- a/backend/druks/browser/sessions.py +++ b/backend/druks/browser/sessions.py @@ -14,7 +14,6 @@ BrowserExportError, BrowserLaunchError, BrowserSessionNotReadyError, - BrowserSessionUnknownError, ) from druks.browser.locks import acquire_writer_lock, release_writer_lock from druks.browser.models import StoredBrowserSession @@ -100,15 +99,24 @@ async def playwright(self): def mark_stale(self) -> None: """Report the login bounced — the site wants the operator back. The pane shows the session as stale; the workflow decides whether to park.""" + self._get_or_create_row().mark_stale() + + def _get_or_create_row(self) -> StoredBrowserSession: + """The declaration's stored half, written the first time a run reaches + for the login. Until then the declaration is the only thing that exists — + the row appears in the sessions pane wanting a login, which is how the + operator learns the extension needs one.""" row = StoredBrowserSession.get_for_name(self.name) - if not row: - raise BrowserSessionUnknownError(self.name) - row.mark_stale() + if row: + return row + return StoredBrowserSession.create( + name=self.name, + payload_format=BrowserSessionPayloadFormat.PROFILE_DIR, + site=self.site, + ) def _ready_row(self) -> StoredBrowserSession: - row = StoredBrowserSession.get_for_name(self.name) - if not row: - raise BrowserSessionUnknownError(self.name) + row = self._get_or_create_row() if row.status != BrowserSessionStatus.READY.value: raise BrowserSessionNotReadyError(self.name, row.status) return row diff --git a/backend/tests/test_browser_borrow.py b/backend/tests/test_browser_borrow.py index 29246eba..7e312b6a 100644 --- a/backend/tests/test_browser_borrow.py +++ b/backend/tests/test_browser_borrow.py @@ -9,7 +9,6 @@ BrowserClientMissingError, BrowserLaunchError, BrowserSessionNotReadyError, - BrowserSessionUnknownError, BrowserSessionWriterLockedError, ) from druks.browser.models import StoredBrowserSession @@ -178,20 +177,25 @@ async def test_persisting_borrow_refuses_a_second_writer(borrow): assert browser.commands == [] -async def test_borrow_requires_a_ready_session(borrow, druks_db): - with pytest.raises(BrowserSessionUnknownError): +async def test_first_borrow_writes_the_declared_session_and_asks_for_a_login(borrow, druks_db): + """Nothing is stored until a run reaches for the login: the first borrow + writes the row so the pane can ask the operator to sign in, and says so.""" + assert not StoredBrowserSession.get_for_name(XMe.docs.name) + + with pytest.raises(BrowserSessionNotReadyError): async with XMe.docs.cdp(): pass - StoredBrowserSession.create( - name=XMe.docs.name, - payload_format=BrowserSessionPayloadFormat.STORAGE_STATE, - site=XMe.docs.site, - ) + row = StoredBrowserSession.get_for_name(XMe.docs.name) + assert row.status == BrowserSessionStatus.NEEDS_LOGIN.value + assert row.site == XMe.docs.site + with pytest.raises(BrowserSessionNotReadyError): async with XMe.docs.cdp(): pass + assert StoredBrowserSession.list_all() == [row] + async def test_launch_failure_raises_and_releases_the_lock(borrow): browser, redis = borrow