diff --git a/.env.example b/.env.example index 22064a7..41ac06b 100644 --- a/.env.example +++ b/.env.example @@ -14,4 +14,6 @@ DAS_DATABASE_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD} ATOMDB_PACKAGE_PATH= QUERY_ENGINE_PACKAGE_PATH= -DAS_KNOWLEDGE_BASE=/data/samples/animals.metta +DAS_METTA_PARSER_VERSION=latest + +DAS_KNOWLEDGE_BASE=/tmp/animals.metta diff --git a/.github/workflows/aws-ci.yml b/.github/workflows/aws-ci.yml deleted file mode 100644 index 63d5c81..0000000 --- a/.github/workflows/aws-ci.yml +++ /dev/null @@ -1,72 +0,0 @@ -# --- -# name: AWS Build & Deployment - -# on: -# workflow_run: -# workflows: ["Versioning"] -# types: [requested] - -# env: -# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} -# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} -# AWS_REGION: us-east-1 -# AWS_S3_BUCKET: das.singularitynet.io -# AWS_S3_BUCKET_KEY: production - -# jobs: -# build: -# runs-on: ubuntu-latest -# steps: -# - name: Checkout Repository -# uses: actions/checkout@v3 - -# - name: Install function requirements -# run: |- -# pip3 install awscli -# for dir in */; do -# if [[ $dir != .* ]]; then -# cd $dir; pip3 install -r ./requirements.txt -t .; cd .. -# fi -# done - -# - name: Download DocumentDB pem -# run: |- -# for dir in */; do -# if [[ $dir != .* ]]; then -# cd $dir; wget https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem; cd .. -# fi -# done - -# - name: Bundle function into a ZIP file -# run: |- -# for dir in */; do -# if [[ $dir != .* ]]; then -# FUNC_NAME=$(basename "$dir") -# cd $dir; zip -r $FUNC_NAME.zip .; cd .. -# fi -# done - -# - name: Push function to s3 -# run: |- -# for dir in */; do -# if [[ $dir != .* ]]; then -# FUNC_NAME=$(basename "$dir") -# cd $dir; aws s3 cp ./$FUNC_NAME.zip s3://${{ env.AWS_S3_BUCKET }}/${{ env.AWS_S3_BUCKET_KEY }}/$FUNC_NAME.zip; cd .. -# fi -# done - -# deploy: -# runs-on: ubuntu-latest -# needs: build -# steps: -# - name: Checkout Repository -# uses: actions/checkout@v3 - -# - name: Update lambda function -# run: |- -# for dir in */; do -# if [[ $dir != .* ]]; then -# FUNC_NAME=$(basename "$dir") -# cd $dir; aws lambda update-function-code --function-name $FUNC_NAME --s3-bucket ${{ env.AWS_S3_BUCKET }} --s3-key ${{ env.AWS_S3_BUCKET_KEY }}/$FUNC_NAME.zip --publish --region ${{ env.AWS_REGION }}; cd .. -# fi -# done diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml deleted file mode 100644 index 2e1bfcd..0000000 --- a/.github/workflows/version.yml +++ /dev/null @@ -1,21 +0,0 @@ -# --- -# name: Versioning - -# on: -# workflow_dispatch: -# inputs: -# version: -# description: "Version" -# required: true - -# jobs: -# tag: -# uses: singnet/das-scripts-pipeline/.github/workflows/action.yml@master -# with: -# version: ${{ github.event.inputs.version }} -# version-strategy: bump-version-from-variable-value -# job-image-namespace: trueagi -# job-image-version-semver: semantic-versioning -# main-branch: master -# version-tag-regex-pattern: /^v\d+\.\d+\.\d+$/ -# version-require-confirmation: "true" diff --git a/.github/workflows/vultr-build.yml b/.github/workflows/vultr-build.yml index e0ff91a..603c405 100644 --- a/.github/workflows/vultr-build.yml +++ b/.github/workflows/vultr-build.yml @@ -13,7 +13,6 @@ on: description: "Select a function to build:" default: das-query-engine options: - - das-atomdb - das-query-engine jobs: diff --git a/das-atomdb/actions.py b/das-atomdb/actions.py deleted file mode 100644 index d30ef35..0000000 --- a/das-atomdb/actions.py +++ /dev/null @@ -1,107 +0,0 @@ -import time -from enum import Enum -from hyperon_das_atomdb.adapters import RedisMongoDB -from typing import Optional - - -class ActionType(str, Enum): - NODE_EXISTS = "node_exists" - LINK_EXISTS = "link_exists" - GET_NODE_HANDLE = "get_node_handle" - GET_LINK_HANDLE = "get_link_handle" - GET_LINK_TARGETS = "get_link_targets" - IS_ORDERED = "is_ordered" - GET_MATCHED_LINKS = "get_matched_links" - GET_ALL_NODES = "get_all_nodes" - GET_MATCHED_TYPE_TEMPLATE = "get_matched_type_template" - GET_MATCHED_TYPE = "get_matched_type" - GET_NODE_NAME = "get_node_name" - GET_MATCHED_NODE_NAME = "get_matched_node_name" - GET_ATOM_AS_DICT = "get_atom_as_dict" - GET_ATOM_AS_DEEP_REPRESENTATION = "get_atom_as_deep_representation" - GET_LINK_TYPE = "get_link_type" - GET_NODE_TYPE = "get_node_type" - COUNT_ATOMS = "count_atoms" - CLEAR_DATABASE = "clear_database" - PING = "ping" - - -class Actions: - def __init__(self) -> None: - start_time = time.time() - self.redis_mongo_db = RedisMongoDB() - end_time = time.time() - print(f"MongoDB time: {end_time - start_time}") - - def node_exists(self, node_type: str, node_name: str) -> bool: - return self.redis_mongo_db.node_exists(node_type, node_name) - - def link_exists(self, link_type: str, target_handles: list) -> bool: - return self.redis_mongo_db.link_exists(link_type, target_handles) - - def get_node_handle(self, node_type: str, node_name: str) -> str: - return self.redis_mongo_db.get_node_handle(node_type, node_name) - - def get_link_handle(self, link_type: str, target_handles: list) -> str: - return self.redis_mongo_db.get_link_handle(link_type, target_handles) - - def get_link_targets(self, link_handle: str) -> list: - return self.redis_mongo_db.get_link_targets(link_handle) - - def is_ordered(self, link_handle: str) -> bool: - return self.redis_mongo_db.is_ordered(link_handle) - - def get_matched_links( - self, - link_type: str, - target_handles: list, - extra_parameters: Optional[dict] = None, - ): - return self.redis_mongo_db.get_matched_links( - link_type, target_handles, extra_parameters - ) - - def get_all_nodes(self, node_type: str, names: bool = False) -> list: - return self.redis_mongo_db.get_all_nodes(node_type, names) - - def get_matched_type_template( - self, - template: list, - extra_parameters: Optional[dict] = None, - ) -> list: - return self.redis_mongo_db.get_matched_type_template(template, extra_parameters) - - def get_matched_type( - self, - link_type: str, - extra_parameters: Optional[dict] = None, - ) -> list: - return self.redis_mongo_db.get_matched_type(link_type, extra_parameters) - - def get_node_name(self, node_handle: str) -> str: - return self.redis_mongo_db.get_node_name(node_handle) - - def get_matched_node_name(self, node_type: str, substring: str) -> str: - return self.redis_mongo_db.get_matched_node_name(node_type, substring) - - def get_atom_as_dict(self, handle, arity=-1) -> dict: - return self.redis_mongo_db.get_atom_as_dict(handle, arity) - - def get_atom_as_deep_representation( - self, - handle: str, - arity=-1, - ) -> str: - return self.redis_mongo_db.get_atom_as_deep_representation(handle, arity) - - def get_link_type(self, link_handle: str) -> str: - return self.redis_mongo_db.get_link_type(link_handle) - - def get_node_type(self, node_handle: str) -> str: - return self.redis_mongo_db.get_node_type(node_handle) - - def count_atoms(self) -> tuple([int, int]): - return self.redis_mongo_db.count_atoms() - - def clear_database(self) -> None: - return self.redis_mongo_db.clear_database() diff --git a/das-atomdb/config.py b/das-atomdb/config.py deleted file mode 100644 index 5253f55..0000000 --- a/das-atomdb/config.py +++ /dev/null @@ -1,32 +0,0 @@ -import os - - -def load_env(): - environments = { - "dasmongodbname": "DAS_MONGODB_NAME", - "dasmongodbport": "DAS_MONGODB_PORT", - "dasmongodbhostname": "DAS_MONGODB_HOSTNAME", - "dasmongodbusername": "DAS_MONGODB_USERNAME", - "dasmongodbpassword": "DAS_MONGODB_PASSWORD", - "dasredishostname": "DAS_REDIS_HOSTNAME", - "dasredisport": "DAS_REDIS_PORT", - "dasredispassword": "DAS_REDIS_PASSWORD", - "dasredisusername": "DAS_REDIS_USERNAME", - "dasmongodbtlscafile": "DAS_MONGODB_TLS_CA_FILE", - "dasuserediscluster": "DAS_USE_REDIS_CLUSTER", - "dasusecachednodes": "DAS_USE_CACHED_NODES", - "dasusecachedlinktypes": "DAS_USE_CACHED_LINK_TYPES", - "dasusecachednodetypes": "DAS_USE_CACHED_NODE_TYPES", - } - - for key, value in environments.items(): - secret = f"/var/openfaas/secrets/{key}" - if os.path.exists(secret): - with open(secret) as f: - os.environ[value] = f.readline().strip() - else: - env_value = os.environ.get(key, None) - os.environ[value] = env_value if isinstance(env_value, str) else "" - - -load_env() diff --git a/das-atomdb/handler.py b/das-atomdb/handler.py deleted file mode 100644 index b215e51..0000000 --- a/das-atomdb/handler.py +++ /dev/null @@ -1,301 +0,0 @@ -import json -import base64 -from config import load_env -from validators.event import EventValidator -from actions import Actions, ActionType -from validators import validate -from validators.actions import ( - NodeExistsValidator, - LinkExistsValidator, - GetNodeHandleValidator, - GetLinkHandleValidator, - GetLinkTargetsValidator, - IsOrderedValidator, - GetMatchedLinksValidator, - GetAllNodeValidator, - GetMatchedTypeTemplateValidator, - GetMatchedTypeValidator, - GetNodeNameValidator, - GetMatchedNodeNameValidator, - GetAtomAsDictValidator, - GetAtomAsDeepRepresentationValidator, - GetLinkTypeValidator, - GetNodeTypeValidator, -) -from hyperon_das_atomdb.exceptions import ( - NodeDoesNotExistException, - LinkDoesNotExistException, -) - -load_env() - - -def _response(http_code_response, result, context): - if context is None: - return result - - return { - "statusCode": http_code_response, - "body": json.dumps(result), - "headers": {"Content-Type": "application/json"}, - } - - -def _get_payload(event: any): - if isinstance(event, str): # vultr - return json.loads(event) - - body = event.get("body", event) # aws - - if isinstance(body, str): - if event.get("isBase64Encoded") is True: - return json.loads(base64.b64decode(body)) - - return json.loads(body) - - return body - - -def handle(event: any, context=None): - payload = validate(EventValidator(), _get_payload(event)) - result = None - actions = None - http_code_response = 200 - - try: - actions = Actions() - except Exception as e: - result = dict(error=str(e)) - http_code_response = 400 - return _response(http_code_response, result, context) - - if payload["action"] == ActionType.NODE_EXISTS: - node_exists_payload = validate( - NodeExistsValidator(), - payload["input"], - ) - try: - result = actions.node_exists( - node_exists_payload["node_type"], - node_exists_payload["node_name"], - ) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.LINK_EXISTS: - link_exists_payload = validate( - LinkExistsValidator(), - payload["input"], - ) - try: - result = actions.link_exists( - link_exists_payload["link_type"], - link_exists_payload["target_handles"], - ) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_NODE_HANDLE: - get_node_handle_payload = validate( - GetNodeHandleValidator(), - payload["input"], - ) - try: - result = actions.get_node_handle( - get_node_handle_payload["node_type"], - get_node_handle_payload["node_name"], - ) - except NodeDoesNotExistException as e: - result = dict(error=e.message) - http_code_response = 404 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_LINK_HANDLE: - get_link_handle_payload = validate( - GetLinkHandleValidator(), - payload["input"], - ) - try: - result = actions.get_link_handle( - get_link_handle_payload["link_type"], - get_link_handle_payload["target_handles"], - ) - except LinkDoesNotExistException as e: - result = dict(error=e.message) - http_code_response = 404 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_LINK_TARGETS: - get_link_targets_payload = validate( - GetLinkTargetsValidator(), - payload["input"], - ) - try: - result = actions.get_link_targets(get_link_targets_payload["link_handle"]) - except ValueError as e: - result = dict(error=e.message) - http_code_response = 400 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.IS_ORDERED: - is_ordered_payload = validate( - IsOrderedValidator(), - payload["input"], - ) - try: - result = actions.is_ordered(is_ordered_payload["link_handle"]) - except ValueError as e: - result = dict(error=e.message) - http_code_response = 400 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_MATCHED_LINKS: - get_matched_links_payload = validate( - GetMatchedLinksValidator(), - payload["input"], - ) - result = actions.get_matched_links( - get_matched_links_payload["link_type"], - get_matched_links_payload["target_handles"], - payload["input"].get("extra_parameters"), - ) - elif payload["action"] == ActionType.GET_ALL_NODES: - get_all_nodes_payload = validate( - GetAllNodeValidator(), - payload["input"], - ) - try: - result = actions.get_all_nodes( - get_all_nodes_payload["node_type"], - get_all_nodes_payload["names"], - ) - except ValueError as e: - result = dict(error=e.message) - http_code_response = 400 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_MATCHED_TYPE_TEMPLATE: - get_matched_type_template_payload = validate( - GetMatchedTypeTemplateValidator(), - payload["input"], - ) - try: - result = actions.get_matched_type_template( - get_matched_type_template_payload["template"], - payload["input"].get("extra_parameters"), - ) - except ValueError as e: - result = dict(error=e.message) - http_code_response = 400 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_MATCHED_TYPE: - get_matched_type_payload = validate( - GetMatchedTypeValidator(), - payload["input"], - ) - try: - result = actions.get_matched_type( - get_matched_type_payload["link_type"], - payload["input"].get("extra_parameters"), - ) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_NODE_NAME: - get_node_name_payload = validate( - GetNodeNameValidator(), - payload["input"], - ) - try: - result = actions.get_node_name(get_node_name_payload["node_handle"]) - except ValueError as e: - result = dict(error=e.message) - http_code_response = 400 - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_MATCHED_NODE_NAME: - get_matched_node_name_payload = validate( - GetMatchedNodeNameValidator(), - payload["input"], - ) - try: - result = actions.get_matched_node_name( - get_matched_node_name_payload["node_type"], - get_matched_node_name_payload["substring"], - ) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_ATOM_AS_DICT: - get_atom_as_dict_payload = validate( - GetAtomAsDictValidator(), - payload["input"], - ) - try: - result = actions.get_atom_as_dict( - get_atom_as_dict_payload["handle"], - get_atom_as_dict_payload["arity"], - ) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_ATOM_AS_DEEP_REPRESENTATION: - get_atom_as_deep_representation_payload = validate( - GetAtomAsDeepRepresentationValidator(), - payload["input"], - ) - try: - result = actions.get_atom_as_deep_representation( - get_atom_as_deep_representation_payload["handle"], - get_atom_as_deep_representation_payload["arity"], - ) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_LINK_TYPE: - get_link_type_payload = validate( - GetLinkTypeValidator(), - payload["input"], - ) - try: - result = actions.get_link_type(get_link_type_payload["link_handle"]) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.GET_NODE_TYPE: - get_node_type_payload = validate( - GetNodeTypeValidator(), - payload["input"], - ) - try: - result = actions.get_node_type(get_node_type_payload["node_handle"]) - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.COUNT_ATOMS: - try: - result = actions.count_atoms() - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.CLEAR_DATABASE: - try: - result = actions.clear_database() - except Exception as e: - result = dict(error=e.message) - http_code_response = 500 - elif payload["action"] == ActionType.PING: - result = dict(message="pong") - else: - result = dict(error=f'The action {payload["action"]} was not found') - http_code_response = 400 - - return _response(http_code_response, result, context) diff --git a/das-atomdb/requirements.txt b/das-atomdb/requirements.txt deleted file mode 100644 index 7ef2755..0000000 --- a/das-atomdb/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -hyperon-das-atomdb~=0.4.1 -incoming==0.3.1 diff --git a/das-atomdb/validators/__init__.py b/das-atomdb/validators/__init__.py deleted file mode 100644 index 9797dc1..0000000 --- a/das-atomdb/validators/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import json -from incoming import PayloadValidator - - -def validate(validator: PayloadValidator, payload: any) -> any: - result, errors = validator.validate(payload) - assert result and errors is None, "Validation failed.\n%s" % json.dumps( - errors, - indent=2, - ) - - return payload diff --git a/das-atomdb/validators/actions.py b/das-atomdb/validators/actions.py deleted file mode 100644 index 0b5969c..0000000 --- a/das-atomdb/validators/actions.py +++ /dev/null @@ -1,77 +0,0 @@ -from incoming import datatypes, PayloadValidator - - -class NodeExistsValidator(PayloadValidator): - node_type = datatypes.String() - node_name = datatypes.String() - - -class LinkExistsValidator(PayloadValidator): - link_type = datatypes.String() - target_handles = datatypes.Array() - - -class GetNodeHandleValidator(PayloadValidator): - node_type = datatypes.String() - node_name = datatypes.String() - - -class GetLinkHandleValidator(PayloadValidator): - link_type = datatypes.String() - target_handles = datatypes.Array() - - -class GetLinkTargetsValidator(PayloadValidator): - link_handle = datatypes.String() - - -class IsOrderedValidator(PayloadValidator): - link_handle = datatypes.String() - - -class GetMatchedLinksValidator(PayloadValidator): - link_type = datatypes.String() - target_handles = datatypes.Array() - # extra_parameters = datatypes.JSON(validate_dict) - - -class GetAllNodeValidator(PayloadValidator): - node_type = datatypes.String() - names = datatypes.Boolean() - - -class GetMatchedTypeTemplateValidator(PayloadValidator): - template = datatypes.Array() - # extra_parameters = datatypes.JSON(validate_dict) - - -class GetMatchedTypeValidator(PayloadValidator): - link_type = datatypes.String() - # extra_parameters = datatypes.JSON(validate_dict) - - -class GetNodeNameValidator(PayloadValidator): - node_handle = datatypes.String() - - -class GetMatchedNodeNameValidator(PayloadValidator): - node_type = datatypes.String() - substring = datatypes.String() - - -class GetAtomAsDictValidator(PayloadValidator): - handle = datatypes.String() - arity = datatypes.Integer() - - -class GetAtomAsDeepRepresentationValidator(PayloadValidator): - handle = datatypes.String() - arity = datatypes.Integer() - - -class GetLinkTypeValidator(PayloadValidator): - link_handle = datatypes.String() - - -class GetNodeTypeValidator(PayloadValidator): - node_handle = datatypes.String() diff --git a/das-atomdb/validators/custom_validator_types.py b/das-atomdb/validators/custom_validator_types.py deleted file mode 100644 index d022ca0..0000000 --- a/das-atomdb/validators/custom_validator_types.py +++ /dev/null @@ -1,2 +0,0 @@ -def validate_dict(val, *args, **kwargs): - return isinstance(val, dict) diff --git a/das-atomdb/validators/event.py b/das-atomdb/validators/event.py deleted file mode 100644 index 1d28c6e..0000000 --- a/das-atomdb/validators/event.py +++ /dev/null @@ -1,7 +0,0 @@ -from incoming import datatypes, PayloadValidator -from validators.custom_validator_types import validate_dict - - -class EventValidator(PayloadValidator): - action = datatypes.String() - input = datatypes.Function(validate_dict) diff --git a/das-query-engine/tests/integration/handle/base_test_action.py b/das-query-engine/tests/integration/handle/base_test_action.py index 2509af4..f8ffa11 100644 --- a/das-query-engine/tests/integration/handle/base_test_action.py +++ b/das-query-engine/tests/integration/handle/base_test_action.py @@ -1,11 +1,21 @@ -import json from abc import ABC, abstractmethod import pytest from handler import UnreachableConnection, handle -@pytest.mark.skip( - reason="Disabled because of das-serverless-function#94" -) + +monkey = '"monkey"' +human = '"human"' +mammal = '"mammal"' + + +symbol = 'Symbol' +concept = 'Concept' +similarity = 'Similarity' +metta_type = 'MettaType' +expression = 'Expression' +inheritance = 'Inheritance' + + class BaseTestHandlerAction(ABC): @abstractmethod def action_type(self): @@ -15,10 +25,6 @@ def action_type(self): def valid_event(self, action_type): pass - @abstractmethod - def expected_output(self): - pass - @pytest.fixture def malformed_event(self): return {"body": {}} @@ -27,33 +33,12 @@ def malformed_event(self): def unknown_action_event(self): return {"body": {"action": "unknown_action", "input": {}}} - @staticmethod - def _sorted_nested(obj): - if isinstance(obj, list): - return sorted(str(BaseTestHandlerAction._sorted_nested(item)) for item in obj) - elif isinstance(obj, dict): - return sorted( - (key, BaseTestHandlerAction._sorted_nested(value)) for key, value in obj.items() - ) - elif isinstance(obj, (int, float, str, bool, type(None))): - return obj - else: - return str(obj) - - @staticmethod - def _compare_nested(obj1, obj2): - return BaseTestHandlerAction._sorted_nested(obj1) == BaseTestHandlerAction._sorted_nested( - obj2 - ) - - def assert_successful_execution(self, valid_event, expected_output): + def make_request(self, valid_event): response = handle(valid_event, context={}) - body = json.loads(response["body"]) - assert response["statusCode"] == 200, f"Assertion failed:\nReceived: {response['statusCode']}\nExpected: 200" - assert BaseTestHandlerAction._compare_nested( - body, - expected_output, - ), f"Assertion failed:\nResponse Body: {response['body']}\nExpected: {json.dumps(expected_output)}" + body = response["body"] + status_code = response["statusCode"] + + return body, status_code def assert_payload_malformed(self, malformed_event): response = handle(malformed_event, context={}) diff --git a/das-query-engine/tests/integration/handle/test_count_atoms_action.py b/das-query-engine/tests/integration/handle/test_count_atoms_action.py index 5f19435..9e27c34 100644 --- a/das-query-engine/tests/integration/handle/test_count_atoms_action.py +++ b/das-query-engine/tests/integration/handle/test_count_atoms_action.py @@ -17,16 +17,19 @@ def valid_event(self, action_type): } } - @pytest.fixture - def expected_output(self): - return [14, 26] - def test_count_atoms_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, \ + f"Assertion failed:\nReceived: {status_code}\nExpected: {expected_status_code}" + + assert isinstance(body, tuple), "body must be a tuple." + assert all(isinstance(item, int) for item in body), "All items in body must be integers." + assert len(body) == 2, "body must contain exactly two elements." def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_get_atom_action.py b/das-query-engine/tests/integration/handle/test_get_atom_action.py index 0a2e4c4..e29887a 100644 --- a/das-query-engine/tests/integration/handle/test_get_atom_action.py +++ b/das-query-engine/tests/integration/handle/test_get_atom_action.py @@ -1,13 +1,11 @@ import pytest from actions import ActionType from hyperon_das_atomdb.utils.expression_hasher import ExpressionHasher -from tests.integration.handle.base_test_action import BaseTestHandlerAction +from tests.integration.handle.base_test_action import BaseTestHandlerAction, human, symbol class TestGetAtomAction(BaseTestHandlerAction): - named_type = "Concept" - terminal_name = "human" - human_handle = ExpressionHasher.terminal_hash(named_type, terminal_name) + human_handle = ExpressionHasher.terminal_hash(symbol, human) @pytest.fixture def action_type(self): @@ -24,22 +22,21 @@ def valid_event(self, action_type): } } - @pytest.fixture - def expected_output(self): - return { - "handle": self.human_handle, - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": self.terminal_name, - "named_type": self.named_type, - "type": self.named_type, - } - def test_get_atom_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + assert isinstance(body, dict), "body must be a dictionary" + assert isinstance(body.get("handle"), str), "'handle' in body must be a string." + assert isinstance(body.get("composite_type_hash"), str), "'composite_type_hash' in body must be a string." + assert isinstance(body.get("name"), str), "'name' in body must be a string." + assert isinstance(body.get("named_type"), str), "'named_type' in body must be a string." + assert isinstance(body.get("type"), str), "'type' in body must be a string." + assert isinstance(body.get("is_literal"), bool), "'is_literal' in body must be a boolean." def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_get_incoming_links.py b/das-query-engine/tests/integration/handle/test_get_incoming_links.py index 555ab40..33da3b2 100644 --- a/das-query-engine/tests/integration/handle/test_get_incoming_links.py +++ b/das-query-engine/tests/integration/handle/test_get_incoming_links.py @@ -1,9 +1,12 @@ import pytest from actions import ActionType -from tests.integration.handle.base_test_action import BaseTestHandlerAction +from tests.integration.handle.base_test_action import BaseTestHandlerAction, symbol, human +from hyperon_das_atomdb.utils.expression_hasher import ExpressionHasher class TestGetIncomingLinksAction(BaseTestHandlerAction): + human_handle = ExpressionHasher.terminal_hash(symbol, human) + @pytest.fixture def action_type(self): return ActionType.GET_INCOMING_LINKS @@ -14,270 +17,58 @@ def valid_event(self, action_type): "body": { "action": action_type, "input": { - "atom_handle": "af12f10f9ae2002a1607ba0b47ba8407", + "atom_handle": self.human_handle, "kwargs": { "targets_document": True, + "no_iterator": True }, }, } } - @pytest.fixture - def expected_output(self): - return [ - [ - { - "handle": "16f7e407087bfa0b35b13d13a1aadcae", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "af12f10f9ae2002a1607ba0b47ba8407", - "4e8e26e3276af8a5c2ac2cc2dc95c6d2", - ], - "type": "Similarity", - }, - [ - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "4e8e26e3276af8a5c2ac2cc2dc95c6d2", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "ent", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - [ - { - "handle": "a45af31b43ee5ea271214338a5a5bd61", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "4e8e26e3276af8a5c2ac2cc2dc95c6d2", - "af12f10f9ae2002a1607ba0b47ba8407", - ], - "type": "Similarity", - }, - [ - { - "handle": "4e8e26e3276af8a5c2ac2cc2dc95c6d2", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "ent", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - [ - { - "handle": "2c927fdc6c0f1272ee439ceb76a6d1a4", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "5b34c54bee150c04f9fa584b899dc030", - "af12f10f9ae2002a1607ba0b47ba8407", - ], - "type": "Similarity", - }, - [ - { - "handle": "5b34c54bee150c04f9fa584b899dc030", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "chimp", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - [ - { - "handle": "b5459e299a5c5e8662c427f7e01b3bf1", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "af12f10f9ae2002a1607ba0b47ba8407", - "5b34c54bee150c04f9fa584b899dc030", - ], - "type": "Similarity", - }, - [ - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "5b34c54bee150c04f9fa584b899dc030", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "chimp", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - [ - { - "handle": "c93e1e758c53912638438e2a7d7f7b7f", - "composite_type_hash": "41c082428b28d7e9ea96160f7fd614ad", - "is_toplevel": True, - "composite_type": [ - "e40489cd1e7102e35469c937e05c8bba", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Inheritance", - "named_type_hash": "e40489cd1e7102e35469c937e05c8bba", - "targets": [ - "af12f10f9ae2002a1607ba0b47ba8407", - "bdfe4e7a431f73386f37c6448afe5840", - ], - "type": "Inheritance", - }, - [ - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "bdfe4e7a431f73386f37c6448afe5840", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "mammal", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - [ - { - "handle": "2a8a69c01305563932b957de4b3a9ba6", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "1cdffc6b0b89ff41d68bec237481d1e1", - "af12f10f9ae2002a1607ba0b47ba8407", - ], - "type": "Similarity", - }, - [ - { - "handle": "1cdffc6b0b89ff41d68bec237481d1e1", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "monkey", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - [ - { - "handle": "bad7472f41a0e7d601ca294eb4607c3a", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "af12f10f9ae2002a1607ba0b47ba8407", - "1cdffc6b0b89ff41d68bec237481d1e1", - ], - "type": "Similarity", - }, - [ - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - }, - { - "handle": "1cdffc6b0b89ff41d68bec237481d1e1", - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "monkey", - "named_type": "Concept", - "type": "Concept", - }, - ], - ], - ] def test_incoming_links_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + assert isinstance(body, list), "body must be a list." + assert len(body) > 0, "body must contain at least one element." + + + for item in body: + assert isinstance(item, tuple), "Each item in body must be a tuple." + assert len(item) == 2, "Each tuple in body must contain two elements." + + item_dict, item_tuple = item + assert isinstance(item_dict, dict), "First element of tuple must be a dictionary." + assert isinstance(item_tuple, list), "Second element of tuple must be a list." + + assert isinstance(item_dict.get("handle"), str), "'handle' in item_dict must be a string." + assert isinstance(item_dict.get("type"), str), "'type' in item_dict must be a string." + assert isinstance(item_dict.get("composite_type_hash"), str), "'composite_type_hash' in item_dict must be a string." + assert isinstance(item_dict.get("is_toplevel"), bool), "'is_toplevel' in item_dict must be a boolean." + assert isinstance(item_dict.get("composite_type"), list), "'composite_type' in item_dict must be a list of strings." + assert all(isinstance(item, str) for item in item_dict.get("composite_type")), "'composite_type' elements in item_dict must be strings." + assert isinstance(item_dict.get("named_type"), str), "'named_type' in item_dict must be a string." + assert isinstance(item_dict.get("named_type_hash"), str), "'named_type_hash' in item_dict must be a string." + assert isinstance(item_dict.get("targets"), list), "'targets' in item_dict must be a list of strings." + assert all(isinstance(item, str) for item in item_dict.get("targets")), "'targets' elements in item_dict must be strings." + + + for atom in item_tuple: + assert isinstance(atom, dict), f"{type(atom)} is not a dictionary." + assert isinstance(atom.get("handle"), str), "'handle' in atom must be a string." + assert isinstance(atom.get("type"), str), "'type' in atom must be a string." + assert isinstance(atom.get("composite_type_hash"), str), "'composite_type_hash' in atom must be a string." + assert isinstance(atom.get("name"), str), "'name' in atom must be a string." + assert isinstance(atom.get("named_type"), str), "'named_type' in atom must be a string." + assert isinstance(atom.get("is_literal"), bool), "'is_literal' in atom must be a boolean." + + def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_get_link_action.py b/das-query-engine/tests/integration/handle/test_get_link_action.py index f8c94fb..c85d3a6 100644 --- a/das-query-engine/tests/integration/handle/test_get_link_action.py +++ b/das-query-engine/tests/integration/handle/test_get_link_action.py @@ -1,8 +1,6 @@ import pytest from actions import ActionType -from hyperon_das_atomdb.utils.expression_hasher import ExpressionHasher -from tests.integration.handle.base_test_action import BaseTestHandlerAction - +from tests.integration.handle.base_test_action import BaseTestHandlerAction, metta_type class TestGetLinkAction(BaseTestHandlerAction): @pytest.fixture @@ -11,45 +9,41 @@ def action_type(self): @pytest.fixture def valid_event(self, action_type): - human_handle = ExpressionHasher.terminal_hash("Concept", "human") - monkey_handle = ExpressionHasher.terminal_hash("Concept", "monkey") - return { "body": { "action": action_type, "input": { - "link_type": "Similarity", - "link_targets": [human_handle, monkey_handle], + "link_type": metta_type, + "link_targets": [ + "a408f6dd446cdd4fa56f82e77fe6c870", + "5e50ef7542bb0fde52aed0d841335790" + ], }, } } - @pytest.fixture - def expected_output(self): - return { - "handle": "bad7472f41a0e7d601ca294eb4607c3a", - "composite_type_hash": "ed73ea081d170e1d89fc950820ce1cee", - "is_toplevel": True, - "composite_type": [ - "a9dea78180588431ec64d6bc4872fdbc", - "d99a604c79ce3c2e76a2f43488d5d4c3", - "d99a604c79ce3c2e76a2f43488d5d4c3", - ], - "named_type": "Similarity", - "named_type_hash": "a9dea78180588431ec64d6bc4872fdbc", - "targets": [ - "af12f10f9ae2002a1607ba0b47ba8407", - "1cdffc6b0b89ff41d68bec237481d1e1", - ], - "type": "Similarity", - } - def test_get_link_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + assert isinstance(body, dict), "body must be a dictionary" + assert isinstance(body.get("handle"), str), "'handle' in body must be a string." + assert isinstance(body.get("composite_type_hash"), str), "'composite_type_hash' in body must be a string." + assert isinstance(body.get("is_toplevel"), bool), "'is_toplevel' in body must be a boolean." + assert isinstance(body.get("composite_type"), list), "'composite_type' in body must be a list." + assert all(isinstance(item, str) for item in body["composite_type"]), "'composite_type' elements in body must be strings." + + assert isinstance(body.get("named_type"), str), "'named_type' in body must be a string." + assert isinstance(body.get("named_type_hash"), str), "'named_type_hash' in body must be a string." + + assert isinstance(body.get("targets"), list), "'targets' in body must be a list." + assert all(isinstance(item, str) for item in body["targets"]), "'targets' elements in body must be strings." + + assert isinstance(body.get("type"), str), "'type' in body must be a string." def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_get_links_action.py b/das-query-engine/tests/integration/handle/test_get_links_action.py index 7b5b05c..4180241 100644 --- a/das-query-engine/tests/integration/handle/test_get_links_action.py +++ b/das-query-engine/tests/integration/handle/test_get_links_action.py @@ -1,6 +1,6 @@ import pytest from actions import ActionType -from tests.integration.handle.base_test_action import BaseTestHandlerAction +from tests.integration.handle.base_test_action import BaseTestHandlerAction, symbol, expression class TestGetLinksAction(BaseTestHandlerAction): @@ -14,34 +14,43 @@ def valid_event(self, action_type): "body": { "action": action_type, "input": { - "link_type": "Inheritance", - "link_targets": [ - "4e8e26e3276af8a5c2ac2cc2dc95c6d2", - "80aff30094874e75028033a38ce677bb", + "link_type": expression, + "target_types": [ + symbol, + symbol, + symbol, ], }, } } - @pytest.fixture - def expected_output(self): - return [ - { - "handle": "ee1c03e6d1f104ccd811cfbba018451a", - "type": "Inheritance", - "targets": [ - "4e8e26e3276af8a5c2ac2cc2dc95c6d2", - "80aff30094874e75028033a38ce677bb", - ], - } - ] def test_get_links_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + + assert isinstance(body, list) + assert len(body) > 0 + assert all(isinstance(item, dict) for item in body), "elements in body must be dicts." + + link = body[0] + + assert isinstance(link.get("handle"), str), "'handle' in link must be a string." + assert isinstance(link.get("type"), str), "'type' in link must be a string." + assert isinstance(link.get("composite_type_hash"), str), "'composite_type_hash' in link must be a string." + assert isinstance(link.get("is_toplevel"), bool), "'is_toplevel' in link must be a boolean." + assert isinstance(link.get("composite_type"), list), "'composite_type' in link must be a list." + assert all(isinstance(item, str) for item in link.get("composite_type")), "'composite_type' elements in link must be strings." + assert isinstance(link.get("named_type"), str), "'named_type' in link must be a string." + assert isinstance(link.get("named_type_hash"), str), "'named_type_hash' in link must be a string." + assert isinstance(link.get("targets"), list), "'targets' in link must be a list." + assert all(isinstance(item, str) for item in link.get("targets")), "'targets' elements in link must be strings." + def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_get_node_action.py b/das-query-engine/tests/integration/handle/test_get_node_action.py index 7ca755d..1dea037 100644 --- a/das-query-engine/tests/integration/handle/test_get_node_action.py +++ b/das-query-engine/tests/integration/handle/test_get_node_action.py @@ -1,7 +1,6 @@ import pytest from actions import ActionType -from hyperon_das_atomdb.utils.expression_hasher import ExpressionHasher -from tests.integration.handle.base_test_action import BaseTestHandlerAction +from tests.integration.handle.base_test_action import BaseTestHandlerAction, human, symbol class TestGetNodeAction(BaseTestHandlerAction): @@ -14,28 +13,26 @@ def valid_event(self, action_type): return { "body": { "action": action_type, - "input": {"node_type": "Concept", "node_name": "human"}, + "input": {"node_type": symbol, "node_name": human}, } } - @pytest.fixture - def expected_output(self): - human_handle = ExpressionHasher.terminal_hash("Concept", "human") - - return { - "handle": human_handle, - "composite_type_hash": "d99a604c79ce3c2e76a2f43488d5d4c3", - "name": "human", - "named_type": "Concept", - "type": "Concept", - } - def test_get_node_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + assert isinstance(body, dict), "body must be a dictionary" + assert isinstance(body.get("handle"), str), "'handle' in body must be a string." + assert isinstance(body.get("composite_type_hash"), str), "'composite_type_hash' in body must be a string." + assert isinstance(body.get("name"), str), "'name' in body must be a string." + assert isinstance(body.get("named_type"), str), "'named_type' in body must be a string." + assert isinstance(body.get("type"), str), "'type' in body must be a string." + assert isinstance(body.get("is_literal"), bool), "'is_literal' in body must be a boolean." + def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_handshake_action.py b/das-query-engine/tests/integration/handle/test_handshake_action.py index db68100..39a5eec 100644 --- a/das-query-engine/tests/integration/handle/test_handshake_action.py +++ b/das-query-engine/tests/integration/handle/test_handshake_action.py @@ -26,16 +26,26 @@ def valid_event(self, action_type): } } - @pytest.fixture - def expected_output(self): - return DistributedAtomSpace.about() - def test_handshake_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + assert isinstance(body, dict), "body must be a dictionary" + assert isinstance(body.get("das"), dict), "'das' in body must be a dictionary." + assert isinstance(body.get("atom_db"), dict), "'atom_db' in body must be a dictionary." + + assert isinstance(body["das"].get("name"), str), "'name' in 'das' must be a string." + assert isinstance(body["das"].get("version"), str), "'version' in 'das' must be a string." + assert isinstance(body["das"].get("summary"), str), "'summary' in 'das' must be a string." + + assert isinstance(body["atom_db"].get("name"), str), "'name' in 'atom_db' must be a string." + assert isinstance(body["atom_db"].get("version"), str), "'version' in 'atom_db' must be a string." + assert isinstance(body["atom_db"].get("summary"), str), "'summary' in 'atom_db' must be a string." + def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_ping_action.py b/das-query-engine/tests/integration/handle/test_ping_action.py index efb33c1..442c0f1 100644 --- a/das-query-engine/tests/integration/handle/test_ping_action.py +++ b/das-query-engine/tests/integration/handle/test_ping_action.py @@ -17,16 +17,18 @@ def valid_event(self, action_type): } } - @pytest.fixture - def expected_output(self): - return {"message": "pong"} - def test_ping_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, f"Unexpected status code: {status_code}. Expected: {expected_status_code}" + assert isinstance(body, dict), "body must be a dictionary" + assert "message" in body, "The dictionary body must contain the key 'message'" + assert body["message"] == "pong", "The value of the key 'message' in body must be 'pong'" + def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/das-query-engine/tests/integration/handle/test_query_action.py b/das-query-engine/tests/integration/handle/test_query_action.py index 39d55a4..cd079bc 100644 --- a/das-query-engine/tests/integration/handle/test_query_action.py +++ b/das-query-engine/tests/integration/handle/test_query_action.py @@ -1,6 +1,7 @@ import pytest from actions import ActionType -from tests.integration.handle.base_test_action import BaseTestHandlerAction +from tests.integration.handle.base_test_action import BaseTestHandlerAction, expression, symbol, mammal, inheritance +from hyperon_das.das import Assignment class TestQueryAction(BaseTestHandlerAction): @@ -16,47 +17,61 @@ def valid_event(self, action_type): "input": { "query": { "atom_type": "link", - "type": "Similarity", + "type": expression, "targets": [ - {"atom_type": "node", "type": "Concept", "name": "human"}, - {"atom_type": "node", "type": "Concept", "name": "monkey"}, + {"atom_type": "node", "type": symbol, "name": inheritance}, + {"atom_type": "variable", "name": "$v1"}, + {"atom_type": "node", "type": symbol, "name": mammal}, ], }, - "parameters": {"no_iterator": True}, }, } } - @pytest.fixture - def expected_output(self): - return [ - [ - None, - { - "handle": "bad7472f41a0e7d601ca294eb4607c3a", - "type": "Similarity", - "targets": [ - { - "handle": "af12f10f9ae2002a1607ba0b47ba8407", - "type": "Concept", - "name": "human", - }, - { - "handle": "1cdffc6b0b89ff41d68bec237481d1e1", - "type": "Concept", - "name": "monkey", - }, - ], - }, - ] - ] - def test_query_action( self, valid_event, - expected_output, ): - self.assert_successful_execution(valid_event, expected_output) + body, status_code = self.make_request(valid_event) + expected_status_code = 200 + + assert status_code == expected_status_code, \ + f"Assertion failed:\nReceived: {status_code}\nExpected: {expected_status_code}" + + assert isinstance(body, list), "body must be a list." + assert len(body) > 0, "body must not be empty." + assert all(isinstance(item, tuple) for item in body), "All items in body must be tuples." + + for item in body: + assert len(item) == 2, "Each item in body must contain two elements." + assignment, query_answer = item + + assert isinstance(assignment, Assignment), "Assignment must be an instance of Assignment." + assert isinstance(query_answer, dict), "query_answer must be a dictionary." + + assert isinstance(query_answer.get("handle"), str), "'handle' in query_answer must be a string." + assert isinstance(query_answer.get("type"), str), "'type' in query_answer must be a string." + assert isinstance(query_answer.get("composite_type_hash"), str), "'composite_type_hash' in query_answer must be a string." + assert isinstance(query_answer.get("is_toplevel"), bool), "'is_toplevel' in query_answer must be a boolean." + assert isinstance(query_answer.get("composite_type"), list), "'composite_type' in query_answer must be a list." + assert all(isinstance(item, str) for item in query_answer.get("composite_type")), "'composite_type' elements in query_answer must be strings." + assert isinstance(query_answer.get("named_type"), str), "'named_type' in query_answer must be a string." + assert isinstance(query_answer.get("named_type_hash"), str), "'named_type_hash' in query_answer must be a string." + assert isinstance(query_answer.get("targets"), list), "'targets' in query_answer must be a list." + + targets = query_answer["targets"] + + for target in targets: + assert isinstance(target, dict), "Each target must be a dictionary." + assert isinstance(target.get("handle"), str), "'handle' in target must be a string." + assert isinstance(target.get("type"), str), "'type' in target must be a string." + assert isinstance(target.get("composite_type_hash"), str), "'composite_type_hash' in target must be a string." + assert isinstance(target.get("name"), str), "'name' in target must be a string." + assert isinstance(target.get("named_type"), str), "'named_type' in target must be a string." + assert isinstance(target.get("is_literal"), bool), "'is_literal' in target must be a boolean." + + + def test_malformed_payload(self, malformed_event): self.assert_payload_malformed(malformed_event) diff --git a/docker-compose.yaml b/docker-compose.yaml index 88ae876..4090ffb 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -35,19 +35,20 @@ services: retries: 5 start_period: 40s - canonical-load: - image: levisingnet/canonical-load:latest # TODO: push this image to trueagie - container_name: das-canonical-load - command: python3 scripts/load_das.py --knowledge-base ${DAS_KNOWLEDGE_BASE} + metta-parser: + image: trueagi/das:${DAS_METTA_PARSER_VERSION}-metta-parser + container_name: das-metta-parser + command: db_loader ${DAS_KNOWLEDGE_BASE} volumes: - - /tmp:/tmp - environment: - - PYTHONPATH=/app + - ./examples/data:/tmp env_file: - .env depends_on: - - redis - - mongodb + mongodb: + condition: service_healthy + redis: + condition: service_healthy + restart: on-failure openfaas: container_name: openfaas diff --git a/examples/data/animals.metta b/examples/data/animals.metta new file mode 100644 index 0000000..1146d46 --- /dev/null +++ b/examples/data/animals.metta @@ -0,0 +1,43 @@ +(: Similarity Type) +(: Concept Type) +(: Inheritance Type) +(: "human" Concept) +(: "monkey" Concept) +(: "chimp" Concept) +(: "snake" Concept) +(: "earthworm" Concept) +(: "rhino" Concept) +(: "triceratops" Concept) +(: "vine" Concept) +(: "ent" Concept) +(: "mammal" Concept) +(: "animal" Concept) +(: "reptile" Concept) +(: "dinosaur" Concept) +(: "plant" Concept) +(Similarity "human" "monkey") +(Similarity "human" "chimp") +(Similarity "chimp" "monkey") +(Similarity "snake" "earthworm") +(Similarity "rhino" "triceratops") +(Similarity "snake" "vine") +(Similarity "human" "ent") +(Inheritance "human" "mammal") +(Inheritance "monkey" "mammal") +(Inheritance "chimp" "mammal") +(Inheritance "mammal" "animal") +(Inheritance "reptile" "animal") +(Inheritance "snake" "reptile") +(Inheritance "dinosaur" "reptile") +(Inheritance "triceratops" "dinosaur") +(Inheritance "earthworm" "animal") +(Inheritance "rhino" "mammal") +(Inheritance "vine" "plant") +(Inheritance "ent" "plant") +(Similarity "monkey" "human") +(Similarity "chimp" "human") +(Similarity "monkey" "chimp") +(Similarity "earthworm" "snake") +(Similarity "triceratops" "rhino") +(Similarity "vine" "snake") +(Similarity "ent" "human")