Skip to content

Commit d462392

Browse files
authored
Merge pull request #3999 from sonivijayk/sonivijayk/fix/issue-3845-credential-auto-store-failure-handling
Issue #3845 fix : auto-store failure going to done state
2 parents 1409034 + cb5ef33 commit d462392

2 files changed

Lines changed: 45 additions & 16 deletions

File tree

acapy_agent/protocols/issue_credential/v2_0/handlers/cred_issue_handler.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,32 @@ async def handle(self, context: RequestContext, responder: BaseResponder):
6868

6969
# Automatically move to next state if flag is set
7070
if context.settings.get("debug.auto_store_credential"):
71+
cred_store_succeeded = False
7172
try:
7273
cred_ex_record = await cred_manager.store_credential(cred_ex_record)
74+
cred_store_succeeded = True
75+
except StorageError as err:
76+
# Leave record in credential-received to allow manual retry
77+
self._logger.exception(
78+
"Auto-store failed; leaving credential in received state"
79+
)
80+
if cred_ex_record:
81+
cred_ex_record.error_msg = err.roll_up
82+
async with context.profile.session() as session:
83+
await cred_ex_record.save(
84+
session,
85+
reason=err.roll_up,
86+
)
7387
except (
7488
BaseModelError,
7589
AnonCredsHolderError,
7690
IndyHolderError,
77-
StorageError,
7891
V20CredManagerError,
7992
) as err:
8093
# treat failure to store as mangled on receipt hence protocol error
81-
self._logger.exception("Error storing issued credential")
94+
self._logger.exception(
95+
"Auto-store failed; abandoning credential exchange"
96+
)
8297
if cred_ex_record:
8398
async with context.profile.session() as session:
8499
await cred_ex_record.save_error_state(
@@ -92,11 +107,11 @@ async def handle(self, context: RequestContext, responder: BaseResponder):
92107
)
93108
)
94109

95-
cred_ack_message = await cred_manager.send_cred_ack(cred_ex_record)
96-
97-
trace_event(
98-
context.settings,
99-
cred_ack_message,
100-
outcome="V20CredIssueHandler.handle.STORE",
101-
perf_counter=r_time,
102-
)
110+
if cred_store_succeeded:
111+
cred_ack_message = await cred_manager.send_cred_ack(cred_ex_record)
112+
trace_event(
113+
context.settings,
114+
cred_ack_message,
115+
outcome="V20CredIssueHandler.handle.STORE",
116+
perf_counter=r_time,
117+
)

acapy_agent/protocols/issue_credential/v2_0/handlers/tests/test_cred_issue_handler.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@ async def test_called_auto_store_x_indy(self):
7575
with mock.patch.object(
7676
test_module, "V20CredManager", autospec=True
7777
) as mock_cred_mgr:
78+
mock_cred_ex = mock.MagicMock(
79+
save_error_state=mock.CoroutineMock(),
80+
save=mock.CoroutineMock(),
81+
)
7882
mock_cred_mgr.return_value = mock.MagicMock(
79-
receive_credential=mock.CoroutineMock(
80-
return_value=mock.MagicMock(save_error_state=mock.CoroutineMock())
81-
),
83+
receive_credential=mock.CoroutineMock(return_value=mock_cred_ex),
8284
store_credential=mock.CoroutineMock(
8385
side_effect=[
8486
test_module.IndyHolderError,
@@ -92,18 +94,25 @@ async def test_called_auto_store_x_indy(self):
9294
self.request_context.connection_ready = True
9395
handler_inst = test_module.V20CredIssueHandler()
9496
responder = MockResponder()
97+
self.request_context.settings["debug.auto_store_credential"] = True
9598

9699
await handler_inst.handle(self.request_context, responder) # holder error
97100
await handler_inst.handle(self.request_context, responder) # storage error
98101

102+
assert mock_cred_mgr.return_value.send_cred_ack.call_count == 0
103+
assert mock_cred_ex.save_error_state.call_count == 1
104+
assert mock_cred_ex.save.call_count == 1
105+
99106
async def test_called_auto_store_x_anoncreds(self):
100107
with mock.patch.object(
101108
test_module, "V20CredManager", autospec=True
102109
) as mock_cred_mgr:
110+
mock_cred_ex = mock.MagicMock(
111+
save_error_state=mock.CoroutineMock(),
112+
save=mock.CoroutineMock(),
113+
)
103114
mock_cred_mgr.return_value = mock.MagicMock(
104-
receive_credential=mock.CoroutineMock(
105-
return_value=mock.MagicMock(save_error_state=mock.CoroutineMock())
106-
),
115+
receive_credential=mock.CoroutineMock(return_value=mock_cred_ex),
107116
store_credential=mock.CoroutineMock(
108117
side_effect=[
109118
test_module.AnonCredsHolderError,
@@ -117,10 +126,15 @@ async def test_called_auto_store_x_anoncreds(self):
117126
self.request_context.connection_ready = True
118127
handler_inst = test_module.V20CredIssueHandler()
119128
responder = MockResponder()
129+
self.request_context.settings["debug.auto_store_credential"] = True
120130

121131
await handler_inst.handle(self.request_context, responder) # holder error
122132
await handler_inst.handle(self.request_context, responder) # storage error
123133

134+
assert mock_cred_mgr.return_value.send_cred_ack.call_count == 0
135+
assert mock_cred_ex.save_error_state.call_count == 1
136+
assert mock_cred_ex.save.call_count == 1
137+
124138
async def test_called_not_ready(self):
125139
with mock.patch.object(
126140
test_module, "V20CredManager", autospec=True

0 commit comments

Comments
 (0)