def test_content_raises(identity: PrivateIdentity) -> None: """Request content to create claims and endorsements for an unique asset.""" asset = Asset(asset_type_id="98765") with pytest.raises(TypeError) as exeinfo: asset.put_request_content(endorser=identity) assert ( str(exeinfo.value) == "missing required keyword argument needed for endorsement: 'claims'" )
def test_content_create_asset_request() -> None: """Request content to create an account.""" request_id = "123456" asset = Asset(asset_type_id="123456") content = json.loads(asset.put_request_content(request_id=request_id)) assert content == { "_type": "CreateAssetRequest", "assetId": asset.asset_id, "assetTypeId": asset.asset_type_id, "requestId": request_id, }
def test_content_create_account(quantity: typing.Union[str, int, float]) -> None: """Request content to create an account.""" request_id = "123456" asset = Asset(asset_type_id="123456", quantity=quantity) # type: ignore[arg-type] content = json.loads(asset.put_request_content(request_id=request_id)) assert content == { "_type": "CreateAssetRequest", "assetId": asset.asset_id, "assetTypeId": asset.asset_type_id, "quantity": str(int(float(quantity))), "requestId": request_id, }
def test_rep_account(quantity: typing.Union[int, float, str]) -> None: """Informal representation of an account.""" asset = Asset(asset_type_id="123456", quantity=quantity) # type: ignore[arg-type] assert ( repr(asset) == f"Asset(asset_type_id='{asset.asset_type_id}', " # type: ignore[arg-type] f"asset_id='{asset.asset_id}', quantity='{int(float(asset.quantity))}')" )
def test_repr() -> None: """Informal representation of an asset.""" asset = Asset(asset_type_id="123456") assert ( repr(asset) == f"Asset(asset_type_id='{asset.asset_type_id}', asset_id='{asset.asset_id}')" )
def read_endorsement( ctx: click.core.Context, identity: str, endorser_id: str, entity_type: str, entity_id: str, asset_type_id: str, claim: str, ) -> None: """Read specific endorsement of a claim (identity, asset type, unique asset).""" if entity_type.lower() == "asset": entity = Asset(asset_type_id=asset_type_id, asset_id=entity_id) else: raise NotImplementedError # pragma: no cover id = _load_identity(identity) client = Client(ctx.obj["url"], id) response = client.get( entity, claim=claim.encode(), endorser_id=endorser_id, request_id=ctx.obj["request_id"], ) print(f"{entity!r}") print(f"{claim!r}") print(f"endorser: {response.endorser_id!r}") # type: ignore[union-attr]
def test_raise_invalid_asset_id(invalid_id: str) -> None: """Raise exception if the provided id contains invalid characters.""" with pytest.raises(ValueError) as excinfo: Asset(asset_id=invalid_id, asset_type_id="123456") assert ( str(excinfo.value) == f"invalid identifier '{invalid_id}' - valid characters are [a-zA-Z0-9._\\-+]" )
def test_node_id_cached( client: Client, mocked_requests_200: respx.MockTransport, ) -> None: """node_id is cached after the first GET request.""" client.get( Asset(asset_type_id="1234567"), claim=b"claim-1", endorser_id=client.identity.identity_id, ) client.get( Asset(asset_type_id="1234567"), claim=b"claim-1", endorser_id=client.identity.identity_id, ) assert mocked_requests_200["read_node_info"].call_count == 1
def create_asset(ctx: click.core.Context, identity: str, asset_type_id: str, asset_id: str) -> None: """Create an asset.""" asset = Asset(asset_type_id=asset_type_id, asset_id=asset_id) id = _load_identity(identity) client = Client(ctx.obj["url"], id) _ = client.put(asset, request_id=ctx.obj["request_id"]) print(f"asset_id: {asset}")
def test_raises_invalid_quantity( invalid_quantity: typing.Union[str, int, float] ) -> None: """Request content to create claims on an unique asset.""" with pytest.raises(ValueError) as excinfo: Asset(asset_type_id="123456", quantity=invalid_quantity), # type: ignore[arg-type] assert ( str(excinfo.value) == f"must be a whole, positive number: '{invalid_quantity}'" )
def register_product(client: Client, tag_type: AssetType, product: Tuple[str, str]) -> None: """Register product on iov42 platform and add product information as claim.""" tag_id, claim = product tag = Asset(asset_id=tag_id, asset_type_id=tag_type.asset_type_id) client.put(tag) print(f"Created tag: {tag_id}") client.put(tag, claims=[claim.encode()], endorse=True) print(f"Tag [{tag_id}]: added enrosement on claim '{claim}'")
def test_content_create_asset_claims_request() -> None: """Request content to create claims on an unique asset.""" request_id = "123456" claims = [b"claim-1", b"claim-2"] asset = Asset(asset_type_id="123456") content = json.loads( asset.put_request_content(claims=claims, request_id=request_id) ) hashed_claims = content.pop("claims") assert content == { "_type": "CreateAssetClaimsRequest", "subjectId": asset.asset_id, "subjectTypeId": asset.asset_type_id, "requestId": request_id, } assert len(hashed_claims) == len(claims) for hc in [hashed_claim(c) for c in claims]: assert hc in hashed_claims
def test_response_asset( client: Client, mocked_requests_200: respx.MockTransport, ) -> None: """Platform response to the request to create an asset type.""" entity = Asset(asset_type_id=str(uuid.uuid4())) response = client.put(entity) assert response.resources == [ # type: ignore[union-attr] "/".join(("/api/v1/asset-types", entity.asset_type_id, "assets", entity.asset_id)) ]
def test_create_asset(alice_client: Client, existing_asset_type_id: str) -> None: """Create an unique asset on an iov42 platform.""" asset = Asset(asset_type_id=existing_asset_type_id) response = alice_client.put(asset) assert ("/".join( ("/api/v1/asset-types", asset.asset_type_id, "assets", asset.asset_id)) == response.resources[0] # type: ignore[union-attr] )
def test_unknown_method(identity: PrivateIdentity) -> None: """We create the request even if the method is bogus.""" request = Request( "FOO", "https://example.org", Asset(asset_type_id="123456"), ) request.add_authentication_header(identity) assert [*request.headers] == [] assert request.url == "https://example.org" assert request.content == b"" assert not hasattr(request, "resource")
def test_read_unique_asset_endorsement_header( client: Client, endorser: PublicIdentity, mocked_requests_200: respx.MockTransport, ) -> None: """GET request has only x-iov42-authentication header.""" asset = Asset(asset_type_id="1234567") client.get(asset, claim=b"claim-1", endorser_id=endorser.identity_id) assert mocked_requests_200["read_asset_endorsement"].call_count == 1 http_request, _ = mocked_requests_200["read_asset_endorsement"].calls[0] assert "x-iov42-authentication" in [*http_request.headers]
def test_create_account(alice_client: Client, existing_quantifiable_asset_type_id: str) -> None: """Create an account on an iov42 platform.""" account = Asset(asset_type_id=existing_quantifiable_asset_type_id, quantity=0) # type: ignore[arg-type] response = alice_client.put(account) assert ("/".join(( "/api/v1/asset-types", account.asset_type_id, "assets", account.asset_id)) == response.resources[0] # type: ignore[union-attr] )
def test_get_node_id( client: Client, mocked_requests_200: respx.MockTransport, ) -> None: """Retrieve node_id on the very first GET request.""" client.get( Asset(asset_type_id="1234567"), claim=b"claim-1", endorser_id=client.identity.identity_id, ) assert client.node_id == "node-1" assert mocked_requests_200["read_node_info"].call_count == 1
def test_content_create_endorsements(identity: PrivateIdentity) -> None: """Request content to create claims and endorsements for an unique asset.""" request_id = "123456" claims = [b"claim-1", b"claim-2"] asset = Asset(asset_type_id="98765") content = json.loads( asset.put_request_content( claims=claims, endorser=identity, request_id=request_id ) ) endorsements = content.pop("endorsements") assert content == { "_type": "CreateAssetEndorsementsRequest", "subjectId": asset.asset_id, "subjectTypeId": asset.asset_type_id, "endorserId": identity.identity_id, "requestId": request_id, } for c, s in endorsements.items(): identity.verify_signature( s, ";".join((asset.asset_id, asset.asset_type_id, c)).encode() )
def test_authentication_header( client: Client, endorser: PublicIdentity, mocked_requests_200: respx.MockTransport, ) -> None: """The x-iov42-authentication header is signed by the identity.""" asset = Asset(asset_type_id="1234567") client.get(asset, claim=b"claim-1", endorser_id=endorser.identity_id) http_request, _ = mocked_requests_200["read_asset_endorsement"].calls[0] authentication = json.loads( iov42_decode(http_request.headers["x-iov42-authentication"].encode())) assert len(authentication) == 3 assert authentication["identityId"] == client.identity.identity_id assert authentication[ "protocolId"] == client.identity.private_key.protocol.name
def test_authentication_header_signature( client: Client, endorser: PublicIdentity, mocked_requests_200: respx.MockTransport, ) -> None: """Signature of x-iov42-authentication header is the signed request URL.""" asset = Asset(asset_type_id="1234567") client.get(asset, claim=b"claim-1", endorser_id=endorser.identity_id) http_request, _ = mocked_requests_200["read_asset_endorsement"].calls[0] authentication = json.loads( iov42_decode(http_request.headers["x-iov42-authentication"].encode())) try: content = http_request.url.raw_path client.identity.verify_signature(authentication["signature"], content) except InvalidSignature: pytest.fail("Signature verification failed")
def create_endorsement( ctx: click.core.Context, identity: str, entity_type: str, entity_id: str, asset_type_id: str, claims: List[str], ) -> None: """Endorse claims about an entity (identity, asset type, unique asset).""" if entity_type.lower() == "asset": entity = Asset(asset_type_id=asset_type_id, asset_id=entity_id) else: raise NotImplementedError # pragma: no cover id = _load_identity(identity) client = Client(ctx.obj["url"], id) claims_bytes = [c.encode() for c in claims] response = client.put(entity, claims=claims_bytes, endorse=True, request_id=ctx.obj["request_id"]) print(f"claims on {entity}: {entity_id}") print(f"affected resources: {response.resources}" ) # type: ignore[union-attr]
def test_account(quantity: typing.Union[int, float, str]) -> None: """Create an account with initial quantity.""" account = Asset(asset_type_id="98765", quantity=quantity) # type: ignore[arg-type] assert account.quantity == str(int(float(quantity)))
def existing_asset(alice_client: Client, existing_asset_type_id: str) -> Asset: """Creates an asset oqned ba Alice on an iov42 platform .""" asset = Asset(asset_type_id=existing_asset_type_id) alice_client.put(asset) return asset
import uuid import pytest from iov42.core import Asset from iov42.core import AssetType from iov42.core import CryptoProtocol from iov42.core import Entity from iov42.core import PrivateIdentity from iov42.core import Request entities = [ PrivateIdentity( CryptoProtocol.SHA256WithECDSA.generate_private_key()).public_identity, AssetType(), Asset(asset_type_id="123456"), ] def id_class_name(value: Entity) -> str: """Provide class name as test identifier.""" return str(value.__class__.__name__) @pytest.mark.parametrize("entity", entities, ids=id_class_name) def test_request_with_id(entity: Entity) -> None: """Request with request_id.""" request = Request("PUT", "https://example.org", entity, request_id="123456")
from iov42.core import Asset from iov42.core import AssetType from iov42.core import Client from iov42.core import CryptoProtocol from iov42.core import Entity from iov42.core import hashed_claim from iov42.core import InvalidSignature from iov42.core import PrivateIdentity from iov42.core._crypto import iov42_decode entities = [ PrivateIdentity( CryptoProtocol.SHA256WithECDSA.generate_private_key()).public_identity, AssetType(), Asset(asset_type_id="123456"), ] def id_class_name(value: typing.Any) -> str: """Provide class name for test identifier.""" return str(value.__class__.__name__) def test_hased_claim() -> None: """Hash of a claim.""" assert "RIREN5QE4J55V0aOmXdmRWOoSV_EIUtf0o_tdF4hInM" == hashed_claim( b"claim-1") @pytest.mark.parametrize("entity", entities, ids=id_class_name)
def test_asset() -> None: """Provide asset ID explicitely.""" asset = Asset(asset_type_id="123456", asset_id="98765") assert asset.asset_id == "98765" assert asset.asset_type_id == "123456"
def test_relative_path() -> None: """Return relative URL where the asset information can be read.""" asset = Asset(asset_type_id="123456") assert asset.resource == "/".join( ("/api/v1/asset-types", asset.asset_type_id, "assets", asset.asset_id) )
def test_asset_generated_id() -> None: """Asset with no ID generates an UUID as ID.""" asset = Asset(asset_type_id="123456") assert uuid.UUID(asset.asset_id)