fix: DeadlineLoginDialog.login() returns True on successful login#1289
fix: DeadlineLoginDialog.login() returns True on successful login#1289crowecawcaw wants to merge 6 commits into
Conversation
exec_() compared the dialog result against QMessageBox.Ok (1024), but a successful login calls self.accept(), which makes exec_() return QDialog.Accepted (1). The comparison never matched, so login() returned False even on success, breaking the documented `if ...login():` usage. Compare against QDialog.DialogCode.Accepted instead. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
Replace the __new__/QMessageBox.__init__ hack that bypassed real construction and patched QMessageBox.exec_ with realistic tests that build the dialog through its full __init__ under qtbot, patching only the api.login backend. Covers success (accept -> True), user cancel (-> False) and login error (-> False). Imports moved to top of file to match sibling dialog tests. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
| successful, False otherwise. | ||
| """ | ||
| return super().exec_() == QMessageBox.Ok | ||
| return super().exec_() == QDialog.DialogCode.Accepted |
There was a problem hiding this comment.
This fixes the close_on_success=True path but regresses the close_on_success=False path.
When close_on_success=False, a successful login does not call self.accept(). Instead handle_login_thread_succeeded (lines 179-185) swaps in a QMessageBox.Ok button and waits for the user to click it. For a QMessageBox, clicking a standard button sets the dialog result to that button's enum value — QMessageBox.Ok (1024) — not QDialog.Accepted (1). So after a genuinely successful login in that mode, super().exec_() returns 1024 and this comparison yields 1024 == 1 → False, incorrectly reporting login failure.
The old == QMessageBox.Ok covered the close_on_success=False success (Ok button) but was wrong for the close_on_success=True success (accept() → 1024 == 1024 was the bug). A correct fix needs to accept both outcomes, e.g.:
result = super().exec_()
return result in (QDialog.DialogCode.Accepted, QMessageBox.Ok)close_on_success=False is part of the public login() / __init__ signature, so this path is reachable by callers. Note the new tests only exercise close_on_success=True, so this regression is not caught.
There was a problem hiding this comment.
Addressed in a801792: exec_() now returns result in (QDialog.DialogCode.Accepted, QMessageBox.Ok), covering both the close_on_success=True path (accept() -> QDialog.Accepted) and the close_on_success=False path (clicking the swapped-in Ok button -> QMessageBox.Ok). Also added test_exec_returns_true_on_success_when_not_closing_on_success to cover the close_on_success=False success path.
close_on_success=False resolves a successful login via QMessageBox.Ok (1024), not QDialog.Accepted (1). Accept both so that path is not reported as failure. Add a test covering the close_on_success=False success path. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
mypy (PySide6 stubs) rejects the shorthand QMessageBox.Ok/Cancel/Close attribute access in test code, where the attr-defined override for deadline.client.ui.* does not apply. Use the fully-qualified QMessageBox.StandardButton members instead. Signed-off-by: Stephen Crowe <6042774+crowecawcaw@users.noreply.github.com>
Fixes:
What was the problem/requirement? (What/Why)
DeadlineLoginDialog.login()returnedFalseeven on a successful login. A successful login callsself.accept(), so the underlyingexec_()returnsQDialog.Accepted(1), but the code compared the result againstQMessageBox.Ok(1024). This broke the documentedif ...login():usage pattern — callers thought every login failed.What was the solution? (How)
Compare
exec_()againstQDialog.DialogCode.Acceptedinstead ofQMessageBox.Ok, so a successful (accepted) login returnsTrueand a cancel/reject returnsFalse.What is the impact of this change?
Callers using the documented
if ...login():pattern now correctly see success.How was this change tested?
Replaced the original isolated test with realistic pytest-qt (
qtbot) tests that constructDeadlineLoginDialogthrough its real__init__and drive the real modalexec_(), patching only theapi.loginbackend (no AWS): success →accept()→True; user-cancel →False; login error →False. This exercises__init__, the background-task start, the success/error/cancel signal handlers, andexec_().test/unit/deadline_client/ui/dialogs/test_deadline_login_dialog.py(3 passed, stable across repeated runs under the default xdist config).Was this change documented?
Does this PR introduce new dependencies?
Is this a breaking change?
No — it fixes the return value to match the documented contract.
Does this change impact security?
No.
Testing
Automated (headless,
QT_QPA_PLATFORM=offscreen, PySide6):test/unit/deadline_client/ui/dialogs/test_deadline_login_dialog.py— 4 passed. These construct the real dialog via__init__(real background task + signal wiring, onlyapi.loginpatched) and drive the real modalexec_():close_on_success=True→accept()→ returns Trueclose_on_success=False→ Ok button clicked → returns Trueapi.loginraises → Close clicked → returns Falsesuper().exec_()directly confirmed the return-value mapping for every relevant result code:QDialog.Accepted(1) → True,QMessageBox.Ok(1024) → True,QDialog.Rejected(0) → False,QMessageBox.Cancel(4194304) → False,QMessageBox.Close(2097152) → False.Not automatable — needs a human click-through (the real browser/SSO login handshake can't be scripted):
DeadlineLoginDialog.login(...)), open the login dialog while logged out and complete a real login with the defaultclose_on_success=True— the dialog should close itself and the caller should see success (e.g. "Logged in successfully" path, not the failure path).close_on_success=False(if a caller uses it): after login the dialog shows "Successfully logged into: ..." with an Ok button; clicking Ok must also report success to the caller.Manually verified (2026-07-23): completed a real browser SSO login through the GUI
DeadlineLoginDialogfrom an editable install of this branch — on success the dialog closed itself and the caller correctly saw a logged-in state (no re-click needed), and cancelling mid-login was correctly treated as not-logged-in.