Skip to content

Commit

Permalink
Add all aggregate tests
Browse files Browse the repository at this point in the history
  • Loading branch information
philogicae committed Jan 30, 2025
1 parent afcc792 commit 7386c60
Show file tree
Hide file tree
Showing 2 changed files with 300 additions and 0 deletions.
82 changes: 82 additions & 0 deletions tests/unit/mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from eth_utils.currency import to_wei
from pydantic import BaseModel

from aleph_client.commands.node import NodeInfo

# Change to Aleph testnet
settings.API_HOST = "https://api.twentysix.testnet.network"

Expand Down Expand Up @@ -43,3 +45,83 @@ def create_mock_load_account():
mock_loader.return_value.update_flow = AsyncMock(return_value=FAKE_FLOW_HASH)
mock_loader.return_value.delete_flow = AsyncMock(return_value=FAKE_FLOW_HASH)
return mock_loader


async def mock_fetch_nodes() -> NodeInfo:
NODE_AGGREGATE = {
"address": "0xa1B3bb7d2332383D96b7796B908fB7f7F3c2Be10",
"data": {
"corechannel": {
"nodes": [
{
"hash": "37bcf3b0de2b95168557dccd757e3fb9310f6182eb35173dd929e535dc8d18cc",
"name": "Aleph.Cloud.One",
"time": 1608436347.148,
"owner": "0x13CA00cD3BB1ded822AFF447a6fEC5ed9DaeCD65",
"score": 0.95672722675568,
"banner": "",
"locked": False,
"reward": "0x462b25B706688a7174d675e4787d2DBEE72aB71f",
"status": "active",
"address": "",
"manager": "",
"picture": "81410c35ea8d31569011c091d7c780e83b8e8d44bf292e6f8bf6316b162dda9e",
"stakers": {
"0x160f9C91858940BEBA3bacAD2Fc1c4D32635913b": 21359.3722761429,
"0x161F0F8d70971EB7fE65Fa3558e48442c338EBde": 16778.2001223581,
"0x2BACCdD22C27F84DE8a8EeC0aB7B2a4766E7C02d": 24072.424430756,
},
"has_bonus": True,
"authorized": [],
"description": "Supporting Aleph from NULS POCM through to running a node. Moshe is a genius!\n\nPowered by Node Forge.",
"performance": 0.915326986415614,
"multiaddress": "/ip4/51.79.82.13/tcp/4025/p2p/QmfKB9q89aCX3wqkiqgis9SHfx2MznGd6LTsqektdKUBg5",
"total_staked": 1032817.18542335,
"score_updated": True,
"stream_reward": "",
"inactive_since": None,
"resource_nodes": [
"d1401d7f2e4487b1b956acf8de6a48de5bc5ed9637516f901dfe4eb9f74ac214",
"3b06f6fb75902821eeeddf713837f6a2d38aedff8a7c66c7fa3192b461df6e6a",
"3fe5eecb0dc99be68e197d1ccf037aa4274d30b0f94f955cf765545bebad33c3",
"179317d603edf7c005286dcb79968be294218fdd73ccee3bef719006a0db664c",
"936d1ac993deef3b09c06674e05aa742f4270ec337b1d60ec8021fccaf8f6479",
],
"decentralization": 0.534862998440633,
"registration_url": "",
"terms_and_conditions": "",
},
],
"resource_nodes": [
{
"hash": "cb764fe80f76cd5ec395952263fcbf0f5d2cc0dfe1ed98c90e13734b3fb2df3e",
"name": "Aleph.im Confidential Host 1",
"time": 1723565390.963,
"type": "compute",
"owner": "0xFeF2b33478f906eDE5ee96110b2342861cF1569A",
"score": 0.931334273816828,
"banner": "",
"locked": False,
"parent": "c5a1295c20d5fb1df638e4ff7dee2239ab88c2843899bd26e4b0200a9f5ca82b",
"reward": "0xFeF2b33478f906eDE5ee96110b2342861cF1569A",
"status": "linked",
"address": "https://coco-1.crn.aleph.sh/",
"manager": "",
"picture": "",
"authorized": "",
"description": "",
"performance": 0.867383529585918,
"multiaddress": "",
"score_updated": True,
"stream_reward": "0xFeF2b33478f906eDE5ee96110b2342861cF1569A",
"inactive_since": None,
"decentralization": 0.991886443254677,
"registration_url": "",
"terms_and_conditions": "",
}
],
}
},
"info": {},
}
return NodeInfo(**NODE_AGGREGATE)
218 changes: 218 additions & 0 deletions tests/unit/test_aggregate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
from __future__ import annotations

import contextlib
import json
from unittest.mock import AsyncMock, MagicMock, patch

import aiohttp
import pytest

from aleph_client.commands.aggregate import (
authorize,
forget,
get,
list_aggregates,
permissions,
post,
revoke,
)

from .mocks import FAKE_ADDRESS_EVM, create_mock_load_account

FAKE_AGGREGATE_DATA = dict(
AI=dict(
subscription="premium",
models=dict(
chatgpt=True,
claude=False,
libertai=True,
),
active=True,
),
security=dict(authorizations=[dict(address=FAKE_ADDRESS_EVM, types=["POST"])]),
)


@contextlib.asynccontextmanager
async def mock_client_session_get(self, aggr_link):
yield AsyncMock(
status=200,
raise_for_status=MagicMock(),
json=AsyncMock(return_value=dict(data=FAKE_AGGREGATE_DATA)),
)


def create_mock_auth_client(return_fetch=FAKE_AGGREGATE_DATA):
mock_auth_client = AsyncMock(
create_aggregate=AsyncMock(return_value=(MagicMock(), "processed")),
fetch_aggregate=AsyncMock(return_value=return_fetch),
)
mock_auth_client_class = MagicMock()
mock_auth_client_class.return_value.__aenter__ = AsyncMock(return_value=mock_auth_client)
return mock_auth_client_class, mock_auth_client


@pytest.mark.parametrize(
ids=["by_key_only", "by_key_and_subkey", "by_key_and_subkeys"],
argnames="args",
argvalues=[
dict(key="AI"), # by key only
dict(key="AI", subkeys="models"), # with subkey
dict(key="AI", subkeys="models,subscription"), # with subkeys
],
)
@pytest.mark.asyncio
async def test_forget(capsys, args):
mock_load_account = create_mock_load_account()
mock_list_aggregates = AsyncMock(return_value=FAKE_AGGREGATE_DATA)
mock_auth_client_class, mock_auth_client = create_mock_auth_client()

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch("aleph_client.commands.aggregate.list_aggregates", mock_list_aggregates)
@patch("aleph_client.commands.aggregate.AuthenticatedAlephHttpClient", mock_auth_client_class)
async def run_forget(aggr_spec):
print() # For better display when pytest -v -s
return await forget(**aggr_spec)

result = await run_forget(args)
assert result is True
mock_load_account.assert_called_once()
if "subkeys" not in args:
mock_list_aggregates.assert_called_once()
mock_auth_client.create_aggregate.assert_called_once()
captured = capsys.readouterr()
assert captured.out.endswith("has been deleted\n")


@pytest.mark.parametrize(
ids=["by_key_only", "by_key_and_subkey"],
argnames="args",
argvalues=[
dict(key="AI", content='{"test": "ok"}'), # by key only
dict(key="AI", subkey="models", content='{"chatgpt": true, "claude": true, "libertai": true}'), # with subkey
],
)
@pytest.mark.asyncio
async def test_post(capsys, args):
mock_load_account = create_mock_load_account()
mock_auth_client_class, mock_auth_client = create_mock_auth_client()

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch("aleph_client.commands.aggregate.AuthenticatedAlephHttpClient", mock_auth_client_class)
async def run_post(aggr_spec):
print() # For better display when pytest -v -s
return await post(**aggr_spec)

result = await run_post(args)
assert result is True
mock_load_account.assert_called_once()
mock_auth_client.create_aggregate.assert_called_once()
captured = capsys.readouterr()
assert captured.out.endswith("has been created/updated\n")


@pytest.mark.parametrize(
ids=["by_key_only", "by_key_and_subkey", "by_key_and_subkeys"],
argnames=["args", "expected"],
argvalues=[
(dict(key="AI"), FAKE_AGGREGATE_DATA["AI"]), # by key only
( # with subkey
dict(key="AI", subkeys="subscription"),
dict(subscription=FAKE_AGGREGATE_DATA["AI"]["subscription"]), # type: ignore
),
( # with subkeys
dict(key="AI", subkeys="subscription,models"),
dict(subscription=FAKE_AGGREGATE_DATA["AI"]["subscription"], models=FAKE_AGGREGATE_DATA["AI"]["models"]), # type: ignore
),
],
)
@pytest.mark.asyncio
async def test_get(capsys, args, expected):
mock_load_account = create_mock_load_account()
mock_auth_client_class, mock_auth_client = create_mock_auth_client(return_fetch=FAKE_AGGREGATE_DATA["AI"])

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch("aleph_client.commands.aggregate.AuthenticatedAlephHttpClient", mock_auth_client_class)
async def run_get(aggr_spec):
print() # For better display when pytest -v -s
return await get(**aggr_spec)

aggregate = await run_get(args)
mock_load_account.assert_called_once()
mock_auth_client.fetch_aggregate.assert_called_once()
captured = capsys.readouterr()
assert aggregate == expected and expected == json.loads(captured.out)


@pytest.mark.asyncio
async def test_list_aggregates():
mock_load_account = create_mock_load_account()

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch.object(aiohttp.ClientSession, "get", mock_client_session_get)
async def run_list_aggregates():
print() # For better display when pytest -v -s
return await list_aggregates(address=FAKE_ADDRESS_EVM)

aggregates = await run_list_aggregates()
mock_load_account.assert_called_once()
assert aggregates == FAKE_AGGREGATE_DATA


@pytest.mark.asyncio
async def test_authorize(capsys):
mock_load_account = create_mock_load_account()
mock_get = AsyncMock(return_value=FAKE_AGGREGATE_DATA["security"])
mock_post = AsyncMock(return_value=True)

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch("aleph_client.commands.aggregate.get", mock_get)
@patch("aleph_client.commands.aggregate.post", mock_post)
async def run_authorize():
print() # For better display when pytest -v -s
return await authorize(address=FAKE_ADDRESS_EVM, types="PROGRAM,FORGET")

await run_authorize()
mock_load_account.assert_called_once()
mock_get.assert_called_once()
mock_post.assert_called_once()
captured = capsys.readouterr()
assert captured.out.endswith(f"Permissions has been added for {FAKE_ADDRESS_EVM}\n")


@pytest.mark.asyncio
async def test_revoke(capsys):
mock_load_account = create_mock_load_account()
mock_get = AsyncMock(return_value=FAKE_AGGREGATE_DATA["security"])
mock_post = AsyncMock(return_value=True)

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch("aleph_client.commands.aggregate.get", mock_get)
@patch("aleph_client.commands.aggregate.post", mock_post)
async def run_revoke():
print() # For better display when pytest -v -s
return await revoke(address=FAKE_ADDRESS_EVM)

await run_revoke()
mock_load_account.assert_called_once()
mock_get.assert_called_once()
mock_post.assert_called_once()
captured = capsys.readouterr()
assert captured.out.endswith(f"Permissions has been deleted for {FAKE_ADDRESS_EVM}\n")


@pytest.mark.asyncio
async def test_permissions():
mock_load_account = create_mock_load_account()
mock_get = AsyncMock(return_value=FAKE_AGGREGATE_DATA["security"])

@patch("aleph_client.commands.aggregate._load_account", mock_load_account)
@patch("aleph_client.commands.aggregate.get", mock_get)
async def run_permissions():
print() # For better display when pytest -v -s
return await permissions(address=FAKE_ADDRESS_EVM, json=True)

authorizations = await run_permissions()
mock_load_account.assert_called_once()
mock_get.assert_called_once()
assert authorizations == FAKE_AGGREGATE_DATA["security"]["authorizations"] # type: ignore

0 comments on commit 7386c60

Please sign in to comment.