Skip to content

Commit 76146aa

Browse files
author
Yuki I
committed
test: resolve the error related to profile context switching
Signed-off-by: Yuki I <[email protected]>
1 parent 1c92c0c commit 76146aa

File tree

2 files changed

+289
-0
lines changed

2 files changed

+289
-0
lines changed

acapy_agent/anoncreds/default/legacy_indy/tests/test_registry.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
RevRegDefValue,
4848
)
4949
from ....models.schema import AnonCredsSchema, GetSchemaResult, SchemaResult
50+
from .....core.profile import Profile
51+
from .....wallet.did_info import DIDInfo
5052

5153
B58 = alphabet if isinstance(alphabet, str) else alphabet.decode("ascii")
5254
INDY_DID = rf"^(did:sov:)?[{B58}]{{21,22}}$"
@@ -905,6 +907,95 @@ async def test_register_revocation_list_with_author_role(
905907
assert mock_create_record.called
906908
assert mock_send_revoc_reg_entry.called
907909

910+
@mock.patch.object(
911+
IndyLedgerRequestsExecutor,
912+
"get_ledger_for_identifier",
913+
return_value=(
914+
"mock_ledger_id",
915+
mock.MagicMock(
916+
spec=BaseLedger,
917+
send_revoc_reg_entry=mock.CoroutineMock(return_value="mock_seq_no"),
918+
__aenter__=mock.CoroutineMock(return_value=mock.MagicMock()),
919+
__aexit__=mock.CoroutineMock(return_value=None),
920+
profile=mock.MagicMock(spec=Profile),
921+
),
922+
),
923+
)
924+
@mock.patch.object(AskarAnonCredsProfileSession, "handle")
925+
async def test_register_revocation_list_passes_profile(
926+
self, mock_askar_handle, mock_get_ledger_for_id
927+
):
928+
"""Test register_revocation_list passes profile kwarg via helper."""
929+
self.profile.inject_or = mock.MagicMock()
930+
931+
test_profile = self.profile
932+
933+
test_rev_reg_def = RevRegDef(
934+
tag="tag",
935+
cred_def_id="IssuerDID:3:CL:1:tag",
936+
value=RevRegDefValue(
937+
max_cred_num=100, public_keys={}, tails_hash="", tails_location=""
938+
),
939+
issuer_id="IssuerDID",
940+
type="CL_ACCUM",
941+
)
942+
test_rev_list = RevList(
943+
issuer_id="IssuerDID",
944+
current_accumulator="dummy_accum_value",
945+
revocation_list=[0],
946+
timestamp=1234567890,
947+
rev_reg_def_id="IssuerDID:4:IssuerDID:3:CL:1:tag:CL_ACCUM:tag",
948+
)
949+
950+
await self.registry.register_revocation_list(
951+
test_profile,
952+
test_rev_reg_def,
953+
test_rev_list,
954+
{},
955+
)
956+
957+
mock_ledger_instance = mock_get_ledger_for_id.return_value[1]
958+
959+
mock_ledger_instance.send_revoc_reg_entry.assert_called_once()
960+
961+
_call_args, call_kwargs = mock_ledger_instance.send_revoc_reg_entry.call_args
962+
963+
assert "profile" in call_kwargs
964+
assert call_kwargs["profile"] is test_profile
965+
assert call_kwargs["write_ledger"] is True
966+
967+
async def test_registry_txn_submit_passes_profile(self):
968+
"""Test registry txn_submit passes profile kwarg to ledger txn_submit."""
969+
mock_ledger = mock.MagicMock(BaseLedger, autospec=True)
970+
mock_ledger.txn_submit = mock.CoroutineMock(return_value="mock_ledger_response")
971+
mock_ledger.__aenter__ = mock.CoroutineMock(return_value=mock_ledger)
972+
mock_ledger.__aexit__ = mock.CoroutineMock(return_value=None)
973+
974+
test_profile = self.profile
975+
test_txn_data = '{"a": 1}'
976+
test_sign_did = mock.MagicMock(spec=DIDInfo)
977+
978+
await self.registry.txn_submit(
979+
ledger=mock_ledger,
980+
ledger_transaction=test_txn_data,
981+
sign=True,
982+
taa_accept=True,
983+
sign_did=test_sign_did,
984+
write_ledger=True,
985+
profile=test_profile,
986+
)
987+
988+
mock_ledger.txn_submit.assert_called_once()
989+
990+
_call_args, call_kwargs = mock_ledger.txn_submit.call_args
991+
992+
assert "profile" in call_kwargs
993+
assert call_kwargs["profile"] is test_profile
994+
assert call_kwargs["sign"] is True
995+
assert call_kwargs["taa_accept"] is True
996+
assert call_kwargs["sign_did"] is test_sign_did
997+
assert call_kwargs["write_ledger"] is True
998+
908999
@mock.patch.object(
9091000
ConnRecord,
9101001
"retrieve_by_id",

acapy_agent/ledger/tests/test_indy_vdr.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,23 @@
2626
VdrError,
2727
)
2828

29+
from ...core.profile import Profile
30+
from ...storage.askar import AskarStorage
31+
from ..util import TAA_ACCEPTED_RECORD_TYPE
32+
2933
WEB = DIDMethod(
3034
name="web",
3135
key_types=[ED25519],
3236
rotation=True,
3337
holder_defined_did=HolderDefinedDid.REQUIRED,
3438
)
3539

40+
TEST_TENANT_DID = "WgWxqztrNooG92RXvxSTWv"
41+
TEST_SCHEMA_SEQ_NO = 4935
42+
TEST_CRED_DEF_TAG = "tenant_tag"
43+
44+
TEST_CRED_DEF_ID = f"{TEST_TENANT_DID}:3:CL:{TEST_SCHEMA_SEQ_NO}:{TEST_CRED_DEF_TAG}"
45+
3646

3747
@pytest.fixture()
3848
async def ledger():
@@ -1265,3 +1275,191 @@ async def test_rotate_did_keypair(self, ledger: IndyVdrLedger):
12651275
):
12661276
ledger.profile.context.injector.bind_instance(DIDMethods, DIDMethods())
12671277
await ledger.rotate_public_did_keypair()
1278+
1279+
async def _create_tenant_profile(
1280+
self, main_profile: Profile, name: str = "tenant"
1281+
) -> Profile:
1282+
"""Helper to create a secondary profile instance for testing."""
1283+
tenant_settings = {
1284+
"wallet.type": main_profile.settings.get("wallet.type", "askar-anoncreds"),
1285+
"auto_provision": True,
1286+
"wallet.name": f"{name}_wallet",
1287+
"wallet.key": f"test_tenant_key_for_{name}",
1288+
"wallet.key_derivation_method": "RAW",
1289+
"default_label": name,
1290+
}
1291+
tenant_profile = await create_test_profile(settings=tenant_settings)
1292+
tenant_profile.context.injector.bind_instance(
1293+
DIDMethods, main_profile.context.injector.inject(DIDMethods)
1294+
)
1295+
tenant_profile.context.injector.bind_instance(BaseCache, InMemoryCache())
1296+
tenant_profile.context.injector.bind_instance(
1297+
KeyTypes, main_profile.context.injector.inject(KeyTypes)
1298+
)
1299+
await tenant_profile.session()
1300+
return tenant_profile
1301+
1302+
@pytest.mark.asyncio
1303+
async def test_submit_signing_uses_passed_profile_context(
1304+
self, ledger: IndyVdrLedger
1305+
):
1306+
"""Test _submit calls sign_message using the passed profile context."""
1307+
1308+
tenant_profile = await self._create_tenant_profile(
1309+
ledger.profile, "submit_tenant"
1310+
)
1311+
1312+
mock_signing_did = DIDInfo("tenant_signer", "tenant_signer_vk", {}, SOV, ED25519)
1313+
1314+
mock_request_obj = mock.MagicMock(spec=indy_vdr.Request)
1315+
mock_request_obj.signature_input = b"data_to_be_signed"
1316+
mock_request_obj.body = json.dumps({"req": "data"})
1317+
mock_request_obj.set_signature = mock.Mock()
1318+
mock_request_obj.set_txn_author_agreement_acceptance = mock.Mock()
1319+
1320+
with mock.patch(
1321+
"acapy_agent.wallet.askar.AskarWallet.sign_message",
1322+
new_callable=mock.CoroutineMock,
1323+
return_value=b"mock_signature_from_patch",
1324+
) as mock_sign_message_patch:
1325+
ledger.get_wallet_public_did = mock.CoroutineMock(
1326+
return_value=mock_signing_did
1327+
)
1328+
ledger.get_latest_txn_author_acceptance = mock.CoroutineMock(return_value={})
1329+
1330+
async with ledger:
1331+
await ledger._submit(
1332+
mock_request_obj,
1333+
sign=True,
1334+
sign_did=mock_signing_did,
1335+
taa_accept=False,
1336+
write_ledger=False,
1337+
profile=tenant_profile,
1338+
)
1339+
1340+
mock_sign_message_patch.assert_awaited_once_with(
1341+
message=b"data_to_be_signed", from_verkey=mock_signing_did.verkey
1342+
)
1343+
mock_request_obj.set_signature.assert_called_once_with(
1344+
b"mock_signature_from_patch"
1345+
)
1346+
1347+
@pytest.mark.asyncio
1348+
async def test_get_wallet_public_did_uses_passed_profile(self, ledger: IndyVdrLedger):
1349+
"""Test get_wallet_public_did uses the explicitly passed profile."""
1350+
tenant_profile = await self._create_tenant_profile(
1351+
ledger.profile, "get_did_tenant"
1352+
)
1353+
mock_tenant_did = DIDInfo("did:sov:tenant_pub", "vk_pub", {}, SOV, ED25519)
1354+
1355+
with mock.patch(
1356+
"acapy_agent.wallet.askar.AskarWallet.get_public_did",
1357+
new_callable=mock.CoroutineMock,
1358+
return_value=mock_tenant_did,
1359+
) as mock_get_public_patch:
1360+
result_did = await ledger.get_wallet_public_did(profile=tenant_profile)
1361+
1362+
assert result_did is mock_tenant_did
1363+
mock_get_public_patch.assert_awaited_once()
1364+
1365+
@pytest.mark.asyncio
1366+
async def test_get_latest_taa_uses_passed_profile(self, ledger: IndyVdrLedger):
1367+
"""Test get_latest_txn_author_acceptance uses the explicitly passed profile."""
1368+
tenant_profile = await self._create_tenant_profile(
1369+
ledger.profile, "get_taa_tenant"
1370+
)
1371+
tenant_profile.context.injector.bind_instance(BaseCache, InMemoryCache())
1372+
1373+
with mock.patch.object(
1374+
AskarStorage, "find_all_records", return_value=[]
1375+
) as mock_find_records_patch:
1376+
result_taa = await ledger.get_latest_txn_author_acceptance(
1377+
profile=tenant_profile
1378+
)
1379+
1380+
mock_find_records_patch.assert_awaited_once()
1381+
call_args, _call_kwargs = mock_find_records_patch.call_args
1382+
assert call_args[0] == TAA_ACCEPTED_RECORD_TYPE
1383+
assert call_args[1] == {"pool_name": ledger.pool_name}
1384+
1385+
assert result_taa == {}
1386+
1387+
@pytest.mark.asyncio
1388+
async def test_send_revoc_reg_entry_uses_passed_profile(self, ledger: IndyVdrLedger):
1389+
"""Test send_revoc_reg_entry passes the correct profile to _submit."""
1390+
tenant_profile = await self._create_tenant_profile(
1391+
ledger.profile, "rev_entry_tenant"
1392+
)
1393+
1394+
async with tenant_profile.session() as session:
1395+
wallet = session.inject(BaseWallet)
1396+
tenant_did = await wallet.create_public_did(SOV, ED25519)
1397+
1398+
test_rev_reg_id = f"{tenant_did.did}:4:{TEST_CRED_DEF_ID}:CL_ACCUM:0"
1399+
test_reg_entry = {"ver": "1.0", "value": {"accum": "test_accum"}}
1400+
1401+
with (
1402+
mock.patch.object(
1403+
IndyVdrLedger,
1404+
"get_revoc_reg_def",
1405+
new=mock.CoroutineMock(
1406+
return_value={"txn": {"data": {"revocDefType": "CL_ACCUM"}}}
1407+
),
1408+
),
1409+
mock.patch.object(
1410+
IndyVdrLedger,
1411+
"_create_revoc_reg_entry_request",
1412+
new=mock.CoroutineMock(
1413+
return_value=mock.MagicMock(spec=indy_vdr.Request)
1414+
),
1415+
),
1416+
mock.patch.object(
1417+
IndyVdrLedger,
1418+
"_submit",
1419+
new=mock.CoroutineMock(return_value={"result": "mock_ok"}),
1420+
) as mock_submit,
1421+
):
1422+
async with ledger:
1423+
await ledger.send_revoc_reg_entry(
1424+
revoc_reg_id=test_rev_reg_id,
1425+
revoc_def_type="CL_ACCUM",
1426+
revoc_reg_entry=test_reg_entry,
1427+
write_ledger=True,
1428+
profile=tenant_profile,
1429+
)
1430+
1431+
mock_submit.assert_awaited_once()
1432+
_, submit_kwargs = mock_submit.call_args
1433+
assert submit_kwargs.get("profile") is tenant_profile
1434+
assert submit_kwargs.get("sign_did").did == tenant_did.did
1435+
1436+
@pytest.mark.asyncio
1437+
async def test_ledger_txn_submit_uses_passed_profile(self, ledger: IndyVdrLedger):
1438+
"""Test ledger txn_submit passes profile kwarg to _submit."""
1439+
tenant_profile = await self._create_tenant_profile(
1440+
ledger.profile, "txn_submit_tenant"
1441+
)
1442+
1443+
ledger._submit = mock.CoroutineMock(
1444+
return_value={"op": "REPLY", "result": {"status": "ok"}}
1445+
)
1446+
1447+
test_txn_data = '{"req": "data"}'
1448+
test_sign_did = mock.MagicMock(spec=DIDInfo)
1449+
1450+
await ledger.txn_submit(
1451+
test_txn_data,
1452+
sign=True,
1453+
sign_did=test_sign_did,
1454+
write_ledger=True,
1455+
profile=tenant_profile,
1456+
)
1457+
1458+
ledger._submit.assert_awaited_once()
1459+
_submit_args, submit_kwargs = ledger._submit.call_args
1460+
assert "profile" in submit_kwargs
1461+
assert submit_kwargs["profile"] is tenant_profile
1462+
assert _submit_args[0] == test_txn_data
1463+
assert submit_kwargs["sign"] is True
1464+
assert submit_kwargs["sign_did"] is test_sign_did
1465+
assert submit_kwargs["write_ledger"] is True

0 commit comments

Comments
 (0)