Skip to content

Commit dd4ee76

Browse files
author
Yuki I
committed
test: add tests to anoncreds cred def revocation fix
1 parent 6fb602e commit dd4ee76

File tree

6 files changed

+309
-3356
lines changed

6 files changed

+309
-3356
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/indy_vdr.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1380,7 +1380,11 @@ async def send_revoc_reg_entry(
13801380
try:
13811381
LOGGER.debug("Submitting to ledger")
13821382
resp = await self._submit(
1383-
request, True, sign_did=did_info, write_ledger=write_ledger
1383+
request,
1384+
True,
1385+
sign_did=did_info,
1386+
write_ledger=write_ledger,
1387+
profile=current_profile,
13841388
)
13851389
LOGGER.debug("Received ledger response")
13861390
return {"result": resp}

acapy_agent/ledger/tests/test_indy_vdr.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,28 @@
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_TENANT_VERKEY = "TenantVerkeyyyyyyyyyyyyyyyyyyyyyy"
42+
TEST_SCHEMA_SEQ_NO = 4935
43+
TEST_CRED_DEF_TAG = "tenant_tag"
44+
TEST_REV_REG_TAG = "rev_tag_1"
45+
46+
TEST_CRED_DEF_ID = f"{TEST_TENANT_DID}:3:CL:{TEST_SCHEMA_SEQ_NO}:{TEST_CRED_DEF_TAG}"
47+
TEST_REV_REG_DEF_ID = (
48+
f"{TEST_TENANT_DID}:4:{TEST_CRED_DEF_ID}:CL_ACCUM:{TEST_REV_REG_TAG}"
49+
)
50+
3651

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

docker/Dockerfile.test

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ WORKDIR /usr/src/app
1111

1212
RUN pip install --no-cache-dir poetry==2.1.1
1313

14-
COPY ./README.md pyproject.toml ./poetry.lock ./
14+
COPY ./README.md pyproject.toml ./
15+
# COPY ./README.md pyproject.toml ./poetry.lock ./
1516
RUN mkdir acapy_agent && touch acapy_agent/__init__.py
1617

1718
ARG all_extras=0

0 commit comments

Comments
 (0)