Skip to content

Commit

Permalink
app, test: add guard against source_widget already gone from dict
Browse files Browse the repository at this point in the history
  • Loading branch information
redshiftzero committed Mar 17, 2020
1 parent a7124a5 commit a610a3e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
13 changes: 9 additions & 4 deletions securedrop_client/gui/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,10 +924,15 @@ def update(self, sources: List[Source]) -> List[str]:
if list_widget and list_widget.source_uuid not in source_uuids:
if list_item.isSelected():
self.setCurrentItem(None)
del self.source_widgets[list_widget.source_uuid]
deleted_uuids.append(list_widget.source_uuid)
self.takeItem(i)
list_widget.deleteLater()

try:
del self.source_widgets[list_widget.source_uuid]
deleted_uuids.append(list_widget.source_uuid)
except KeyError:
pass
finally:
self.takeItem(i)
list_widget.deleteLater()

# Create new widgets for new sources
widget_uuids = [self.itemWidget(self.item(i)).source_uuid for i in range(self.count())]
Expand Down
39 changes: 39 additions & 0 deletions tests/gui/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,45 @@ def test_SourceList_update_when_source_deleted(mocker, session, session_maker, h
assert len(sl.source_widgets) == 0


def test_SourceList_update_when_source_deleted_crash(mocker, session, session_maker, homedir):
"""
When SourceList.update calls SourceWidget.update and that
SourceWidget has been deleted from the dict on the SourceList,
it should handle the exception and delete the list widget.
"""
mock_gui = mocker.MagicMock()
controller = logic.Controller('http://localhost', mock_gui, session_maker, homedir)

# create the source in another session
source = factory.Source()
session.add(source)
session.commit()

# construct the SourceWidget with the source fetched in its
# controller's session
oss = controller.session.query(db.Source).filter_by(id=source.id).one()

# add it to the SourceList
sl = SourceList()
sl.setup(controller)
deleted_uuids = sl.update([oss])
assert not deleted_uuids
assert len(sl.source_widgets) == 1
assert sl.count() == 1

# Remove source_widget from dict
sl.source_widgets.pop(oss.uuid)

# now delete it
session.delete(source)
session.commit()

# and finally verify that updating does not throw an exception, and
# all widgets are removed from the list view.
deleted_uuids = sl.update([])
assert sl.count() == 0


def test_SourceList_update_maintains_selection(mocker):
"""
Maintains the selected item if present in new list
Expand Down

0 comments on commit a610a3e

Please sign in to comment.