Skip to content

Commit e3e2496

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

File tree

2 files changed

+344
-0
lines changed

2 files changed

+344
-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}}$"
@@ -1215,3 +1217,92 @@ async def test_get_schem_info(self):
12151217
assert result.issuer_id == "XduBsoPyEA4szYMy3pZ8De"
12161218
assert result.name == "minimal-33279d005748b3cc"
12171219
assert result.version == "1.0"
1220+
1221+
@mock.patch.object(
1222+
IndyLedgerRequestsExecutor,
1223+
"get_ledger_for_identifier",
1224+
return_value=(
1225+
"mock_ledger_id",
1226+
mock.MagicMock(
1227+
spec=BaseLedger,
1228+
send_revoc_reg_entry=mock.CoroutineMock(return_value="mock_seq_no"),
1229+
__aenter__=mock.CoroutineMock(return_value=mock.MagicMock()),
1230+
__aexit__=mock.CoroutineMock(return_value=None),
1231+
profile=mock.MagicMock(spec=Profile),
1232+
),
1233+
),
1234+
)
1235+
@mock.patch.object(AskarAnonCredsProfileSession, "handle")
1236+
async def test_register_revocation_list_passes_profile(
1237+
self, mock_askar_handle, mock_get_ledger_for_id
1238+
):
1239+
"""Test register_revocation_list passes profile kwarg via helper."""
1240+
self.profile.inject_or = mock.MagicMock()
1241+
1242+
test_profile = self.profile
1243+
1244+
test_rev_reg_def = RevRegDef(
1245+
tag="tag",
1246+
cred_def_id="IssuerDID:3:CL:1:tag",
1247+
value=RevRegDefValue(
1248+
max_cred_num=100, public_keys={}, tails_hash="", tails_location=""
1249+
),
1250+
issuer_id="IssuerDID",
1251+
type="CL_ACCUM",
1252+
)
1253+
test_rev_list = RevList(
1254+
issuer_id="IssuerDID",
1255+
current_accumulator="dummy_accum_value",
1256+
revocation_list=[0],
1257+
timestamp=1234567890,
1258+
rev_reg_def_id="IssuerDID:4:IssuerDID:3:CL:1:tag:CL_ACCUM:tag",
1259+
)
1260+
1261+
await self.registry.register_revocation_list(
1262+
test_profile,
1263+
test_rev_reg_def,
1264+
test_rev_list,
1265+
{},
1266+
)
1267+
1268+
mock_ledger_instance = mock_get_ledger_for_id.return_value[1]
1269+
1270+
mock_ledger_instance.send_revoc_reg_entry.assert_called_once()
1271+
1272+
_call_args, call_kwargs = mock_ledger_instance.send_revoc_reg_entry.call_args
1273+
1274+
assert "profile" in call_kwargs
1275+
assert call_kwargs["profile"] is test_profile
1276+
assert call_kwargs["write_ledger"] is True
1277+
1278+
async def test_registry_txn_submit_passes_profile(self):
1279+
"""Test registry txn_submit passes profile kwarg to ledger txn_submit."""
1280+
mock_ledger = mock.MagicMock(BaseLedger, autospec=True)
1281+
mock_ledger.txn_submit = mock.CoroutineMock(return_value="mock_ledger_response")
1282+
mock_ledger.__aenter__ = mock.CoroutineMock(return_value=mock_ledger)
1283+
mock_ledger.__aexit__ = mock.CoroutineMock(return_value=None)
1284+
1285+
test_profile = self.profile
1286+
test_txn_data = '{"a": 1}'
1287+
test_sign_did = mock.MagicMock(spec=DIDInfo)
1288+
1289+
await self.registry.txn_submit(
1290+
ledger=mock_ledger,
1291+
ledger_transaction=test_txn_data,
1292+
sign=True,
1293+
taa_accept=True,
1294+
sign_did=test_sign_did,
1295+
write_ledger=True,
1296+
profile=test_profile,
1297+
)
1298+
1299+
mock_ledger.txn_submit.assert_called_once()
1300+
1301+
_call_args, call_kwargs = mock_ledger.txn_submit.call_args
1302+
1303+
assert "profile" in call_kwargs
1304+
assert call_kwargs["profile"] is test_profile
1305+
assert call_kwargs["sign"] is True
1306+
assert call_kwargs["taa_accept"] is True
1307+
assert call_kwargs["sign_did"] is test_sign_did
1308+
assert call_kwargs["write_ledger"] is True

acapy_agent/ledger/tests/test_indy_vdr.py

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from ...wallet.did_info import DIDInfo
1414
from ...wallet.did_method import SOV, DIDMethod, DIDMethods, HolderDefinedDid
1515
from ...wallet.did_posture import DIDPosture
16+
from ...wallet.error import WalletNotFoundError
1617
from ...wallet.key_type import ED25519, KeyTypes
1718
from ..endpoint_type import EndpointType
1819
from ..indy_vdr import (
@@ -26,13 +27,23 @@
2627
VdrError,
2728
)
2829

30+
from ...core.profile import Profile
31+
from ...storage.askar import AskarStorage
32+
from ..util import TAA_ACCEPTED_RECORD_TYPE
33+
2934
WEB = DIDMethod(
3035
name="web",
3136
key_types=[ED25519],
3237
rotation=True,
3338
holder_defined_did=HolderDefinedDid.REQUIRED,
3439
)
3540

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

3748
@pytest.fixture()
3849
async def ledger():
@@ -1265,3 +1276,245 @@ async def test_rotate_did_keypair(self, ledger: IndyVdrLedger):
12651276
):
12661277
ledger.profile.context.injector.bind_instance(DIDMethods, DIDMethods())
12671278
await ledger.rotate_public_did_keypair()
1279+
1280+
async def _create_tenant_profile(
1281+
self, main_profile: Profile, name: str = "tenant"
1282+
) -> Profile:
1283+
"""Helper to create a secondary profile instance for testing."""
1284+
tenant_settings = {
1285+
"wallet.type": main_profile.settings.get("wallet.type", "askar-anoncreds"),
1286+
"auto_provision": True,
1287+
"wallet.name": f"{name}_wallet",
1288+
"wallet.key": f"test_tenant_key_for_{name}",
1289+
"wallet.key_derivation_method": "RAW",
1290+
"default_label": name,
1291+
}
1292+
tenant_profile = await create_test_profile(settings=tenant_settings)
1293+
tenant_profile.context.injector.bind_instance(
1294+
DIDMethods, main_profile.context.injector.inject(DIDMethods)
1295+
)
1296+
tenant_profile.context.injector.bind_instance(BaseCache, InMemoryCache())
1297+
tenant_profile.context.injector.bind_instance(
1298+
KeyTypes, main_profile.context.injector.inject(KeyTypes)
1299+
)
1300+
await tenant_profile.session()
1301+
return tenant_profile
1302+
1303+
@pytest.mark.asyncio
1304+
async def test_submit_signing_uses_passed_profile_context(
1305+
self, ledger: IndyVdrLedger
1306+
):
1307+
"""Test _submit calls sign_message using the passed profile context."""
1308+
1309+
tenant_profile = await self._create_tenant_profile(
1310+
ledger.profile, "submit_tenant"
1311+
)
1312+
1313+
mock_signing_did = DIDInfo("tenant_signer", "tenant_signer_vk", {}, SOV, ED25519)
1314+
1315+
mock_request_obj = mock.MagicMock(spec=indy_vdr.Request)
1316+
mock_request_obj.signature_input = b"data_to_be_signed"
1317+
mock_request_obj.body = json.dumps({"req": "data"})
1318+
mock_request_obj.set_signature = mock.Mock()
1319+
mock_request_obj.set_txn_author_agreement_acceptance = mock.Mock()
1320+
1321+
with mock.patch(
1322+
"acapy_agent.wallet.askar.AskarWallet.sign_message",
1323+
new_callable=mock.CoroutineMock,
1324+
return_value=b"mock_signature_from_patch",
1325+
) as mock_sign_message_patch:
1326+
ledger.get_wallet_public_did = mock.CoroutineMock(
1327+
return_value=mock_signing_did
1328+
)
1329+
ledger.get_latest_txn_author_acceptance = mock.CoroutineMock(return_value={})
1330+
1331+
async with ledger:
1332+
await ledger._submit(
1333+
mock_request_obj,
1334+
sign=True,
1335+
sign_did=mock_signing_did,
1336+
taa_accept=False,
1337+
write_ledger=False,
1338+
profile=tenant_profile,
1339+
)
1340+
1341+
mock_sign_message_patch.assert_awaited_once_with(
1342+
message=b"data_to_be_signed", from_verkey=mock_signing_did.verkey
1343+
)
1344+
mock_request_obj.set_signature.assert_called_once_with(
1345+
b"mock_signature_from_patch"
1346+
)
1347+
1348+
@pytest.mark.asyncio
1349+
async def test_get_wallet_public_did_uses_passed_profile(self, ledger: IndyVdrLedger):
1350+
"""Test get_wallet_public_did uses the explicitly passed profile."""
1351+
tenant_profile = await self._create_tenant_profile(
1352+
ledger.profile, "get_did_tenant"
1353+
)
1354+
mock_tenant_did = DIDInfo("did:sov:tenant_pub", "vk_pub", {}, SOV, ED25519)
1355+
1356+
with mock.patch(
1357+
"acapy_agent.wallet.askar.AskarWallet.get_public_did",
1358+
new_callable=mock.CoroutineMock,
1359+
return_value=mock_tenant_did,
1360+
) as mock_get_public_patch:
1361+
result_did = await ledger.get_wallet_public_did(profile=tenant_profile)
1362+
1363+
assert result_did is mock_tenant_did
1364+
mock_get_public_patch.assert_awaited_once()
1365+
1366+
@pytest.mark.asyncio
1367+
async def test_get_latest_taa_uses_passed_profile(self, ledger: IndyVdrLedger):
1368+
"""Test get_latest_txn_author_acceptance uses the explicitly passed profile."""
1369+
tenant_profile = await self._create_tenant_profile(
1370+
ledger.profile, "get_taa_tenant"
1371+
)
1372+
tenant_profile.context.injector.bind_instance(BaseCache, InMemoryCache())
1373+
1374+
with mock.patch.object(
1375+
AskarStorage, "find_all_records", return_value=[]
1376+
) as mock_find_records_patch:
1377+
result_taa = await ledger.get_latest_txn_author_acceptance(
1378+
profile=tenant_profile
1379+
)
1380+
1381+
mock_find_records_patch.assert_awaited_once()
1382+
call_args, _call_kwargs = mock_find_records_patch.call_args
1383+
assert call_args[0] == TAA_ACCEPTED_RECORD_TYPE
1384+
assert call_args[1] == {"pool_name": ledger.pool_name}
1385+
1386+
assert result_taa == {}
1387+
1388+
@pytest.mark.asyncio
1389+
async def test_send_revoc_reg_entry_uses_passed_profile(self, ledger: IndyVdrLedger):
1390+
"""Test send_revoc_reg_entry passes the correct profile to _submit."""
1391+
tenant_profile = await self._create_tenant_profile(
1392+
ledger.profile, "rev_entry_tenant"
1393+
)
1394+
1395+
async with tenant_profile.session() as session:
1396+
wallet = session.inject(BaseWallet)
1397+
tenant_did = await wallet.create_public_did(SOV, ED25519)
1398+
1399+
test_rev_reg_id = f"{tenant_did.did}:4:{TEST_CRED_DEF_ID}:CL_ACCUM:0"
1400+
test_reg_entry = {"ver": "1.0", "value": {"accum": "test_accum"}}
1401+
1402+
with (
1403+
mock.patch.object(
1404+
IndyVdrLedger,
1405+
"get_revoc_reg_def",
1406+
new=mock.CoroutineMock(
1407+
return_value={"txn": {"data": {"revocDefType": "CL_ACCUM"}}}
1408+
),
1409+
),
1410+
mock.patch.object(
1411+
IndyVdrLedger,
1412+
"_create_revoc_reg_entry_request",
1413+
new=mock.CoroutineMock(
1414+
return_value=mock.MagicMock(spec=indy_vdr.Request)
1415+
),
1416+
),
1417+
mock.patch.object(
1418+
IndyVdrLedger,
1419+
"_submit",
1420+
new=mock.CoroutineMock(return_value={"result": "mock_ok"}),
1421+
) as mock_submit,
1422+
):
1423+
async with ledger:
1424+
await ledger.send_revoc_reg_entry(
1425+
revoc_reg_id=test_rev_reg_id,
1426+
revoc_def_type="CL_ACCUM",
1427+
revoc_reg_entry=test_reg_entry,
1428+
write_ledger=True,
1429+
profile=tenant_profile,
1430+
)
1431+
1432+
mock_submit.assert_awaited_once()
1433+
_, submit_kwargs = mock_submit.call_args
1434+
assert submit_kwargs.get("profile") is tenant_profile
1435+
assert submit_kwargs.get("sign_did").did == tenant_did.did
1436+
1437+
@pytest.mark.asyncio
1438+
async def test_ledger_txn_submit_uses_passed_profile(self, ledger: IndyVdrLedger):
1439+
"""Test ledger txn_submit passes profile kwarg to _submit."""
1440+
tenant_profile = await self._create_tenant_profile(
1441+
ledger.profile, "txn_submit_tenant"
1442+
)
1443+
1444+
ledger._submit = mock.CoroutineMock(
1445+
return_value={"op": "REPLY", "result": {"status": "ok"}}
1446+
)
1447+
1448+
test_txn_data = '{"req": "data"}'
1449+
test_sign_did = mock.MagicMock(spec=DIDInfo)
1450+
1451+
await ledger.txn_submit(
1452+
test_txn_data,
1453+
sign=True,
1454+
sign_did=test_sign_did,
1455+
write_ledger=True,
1456+
profile=tenant_profile,
1457+
)
1458+
1459+
ledger._submit.assert_awaited_once()
1460+
_submit_args, submit_kwargs = ledger._submit.call_args
1461+
assert "profile" in submit_kwargs
1462+
assert submit_kwargs["profile"] is tenant_profile
1463+
assert _submit_args[0] == test_txn_data
1464+
assert submit_kwargs["sign"] is True
1465+
assert submit_kwargs["sign_did"] is test_sign_did
1466+
assert submit_kwargs["write_ledger"] is True
1467+
1468+
@pytest.mark.asyncio
1469+
async def test_submit_wallet_not_found_error(self, ledger: IndyVdrLedger):
1470+
async with ledger.profile.session() as session:
1471+
wallet = session.inject(BaseWallet)
1472+
test_did = await wallet.create_public_did(SOV, ED25519)
1473+
# Create a DID not present in the wallet
1474+
invalid_did = DIDInfo(
1475+
did="did:sov:invalid",
1476+
verkey="invalid_verkey",
1477+
metadata={},
1478+
method=SOV,
1479+
key_type=ED25519,
1480+
)
1481+
async with ledger:
1482+
test_msg = indy_vdr.ledger.build_get_txn_request(test_did.did, 1, 1)
1483+
with pytest.raises(WalletNotFoundError):
1484+
await ledger._submit(
1485+
test_msg, sign=True, sign_did=invalid_did, write_ledger=False
1486+
)
1487+
1488+
@pytest.mark.asyncio
1489+
async def test_submit_unexpected_error(self, ledger: IndyVdrLedger):
1490+
async with ledger.profile.session() as session:
1491+
wallet = session.inject(BaseWallet)
1492+
test_did = await wallet.create_public_did(SOV, ED25519)
1493+
async with ledger:
1494+
test_msg = indy_vdr.ledger.build_get_txn_request(test_did.did, 1, 1)
1495+
ledger.pool_handle.submit_request.side_effect = ValueError("Unexpected error")
1496+
with pytest.raises(LedgerTransactionError) as exc_info:
1497+
await ledger._submit(test_msg)
1498+
assert "Unexpected error during ledger submission" in str(exc_info.value)
1499+
assert isinstance(exc_info.value.__cause__, ValueError)
1500+
1501+
@pytest.mark.asyncio
1502+
async def test_txn_submit_passes_profile(self, ledger: IndyVdrLedger):
1503+
tenant_profile = await self._create_tenant_profile(
1504+
ledger.profile, "submit_tenant"
1505+
)
1506+
test_txn_data = '{"req": "data"}'
1507+
mock_sign_did = mock.MagicMock(spec=DIDInfo)
1508+
ledger._submit = mock.CoroutineMock(return_value={"result": "ok"})
1509+
1510+
await ledger.txn_submit(
1511+
test_txn_data,
1512+
sign=True,
1513+
sign_did=mock_sign_did,
1514+
write_ledger=True,
1515+
profile=tenant_profile,
1516+
)
1517+
1518+
ledger._submit.assert_awaited_once()
1519+
_, kwargs = ledger._submit.call_args
1520+
assert kwargs.get("profile") == tenant_profile

0 commit comments

Comments
 (0)