diff --git a/synprov/graph/__init__.py b/synprov/graph/__init__.py index 24d9bf7..af9421e 100644 --- a/synprov/graph/__init__.py +++ b/synprov/graph/__init__.py @@ -1,3 +1,4 @@ from .models.activity import GraphActivity from .models.agent import GraphAgent -from .models.reference import GraphReference \ No newline at end of file +from .models.reference import GraphReference +from .builder import ActivityBuilder \ No newline at end of file diff --git a/synprov/graph/builder.py b/synprov/graph/builder.py index 98b8e48..c530732 100644 --- a/synprov/graph/builder.py +++ b/synprov/graph/builder.py @@ -105,4 +105,4 @@ def save(self): rel.create() self.gdb.create_relationship(rel) - return True \ No newline at end of file + return self._find_activity() \ No newline at end of file diff --git a/synprov/graph/controllers/activities_controller.py b/synprov/graph/controllers/activities_controller.py index d08a412..9285d45 100644 --- a/synprov/graph/controllers/activities_controller.py +++ b/synprov/graph/controllers/activities_controller.py @@ -7,7 +7,7 @@ from py2neo import Node, NodeMatcher from synprov.config import neo4j_connection as graph -from synprov.graph import GraphActivity, GraphReference, GraphAgent +from synprov.graph import ActivityBuilder from synprov.util import neo4j_to_d3 @@ -21,11 +21,16 @@ def create_activity(body=None): # noqa: E501 :rtype: Activity """ - # act = Activity(**humps.decamelize(body)) - # act.save() - - # return act.node - return 'Not Implemented', 501 + builder = ActivityBuilder( + **body.to_dict() + ) + act_node = builder.save() + print(act_node) + return humps.camelize({ + 'id': str(act_node.identity), + 'labels': list(act_node.labels), + 'properties': dict(act_node) + }) def get_activities_graph(sort_by=None, order=None, limit=None): # noqa: E501 @@ -61,7 +66,7 @@ def get_activities_graph(sort_by=None, order=None, limit=None): # noqa: E501 results = graph.run( query_base, ) - return neo4j_to_d3(results.data()) + return humps.camelize(neo4j_to_d3(results.data())) def get_agent_subgraph(id, sort_by=None, order=None, limit=None): # noqa: E501 @@ -100,7 +105,7 @@ def get_agent_subgraph(id, sort_by=None, order=None, limit=None): # noqa: E501 query_base, id=id ) - return neo4j_to_d3(results.data()) + return humps.camelize(neo4j_to_d3(results.data())) def get_reference_subgraph(id, @@ -150,4 +155,4 @@ def get_reference_subgraph(id, query_base, id=id ) - return neo4j_to_d3(results.data()) \ No newline at end of file + return humps.camelize(neo4j_to_d3(results.data())) \ No newline at end of file diff --git a/synprov/test/conftest.py b/synprov/test/conftest.py index 6124289..5f83f62 100644 --- a/synprov/test/conftest.py +++ b/synprov/test/conftest.py @@ -36,7 +36,7 @@ def mock_graph(): def mock_graph_data(mock_graph): logger.info("setup: populating graph database") graph = mock_graph - random.seed(0) + random.seed(1) gc = GraphClient(graph) create_mock_graph(gc, 5) yield graph @@ -46,24 +46,24 @@ def mock_graph_data(mock_graph): def mock_activity_form(): used = [ { - 'name': 'Reference_5', - 'target_id': 'TargetID_5', + 'name': 'Reference_3', + 'target_id': 'TargetID_3', 'target_version_id': '1.0', '_class': 'Resource', 'subclass': 'File' + }, + { + 'name': 'Reference_4', + 'target_id': 'TargetID_4', + 'target_version_id': '1.0', + '_class': 'Tool', + 'subclass': 'Tool' } - # { - # 'name': 'Reference_5', - # 'target_id': 'TargetID_5', - # 'target_version_id': '1.0', - # '_class': 'Tool', - # 'subclass': 'Tool' - # } ] generated = [ { - 'name': 'Reference_6', - 'target_id': 'TargetID_6', + 'name': 'Reference_5', + 'target_id': 'TargetID_5', 'target_version_id': '1.0', '_class': 'Resource', 'subclass': 'State' @@ -71,12 +71,12 @@ def mock_activity_form(): ] agents = [ { - 'name': 'User_2', - 'user_id': 'UserID_2' + 'name': 'User_1', + 'user_id': 'UserID_1' } ] form = { - 'name': 'Activity_3', + 'name': 'Activity_2', '_class': 'Tool session', 'agents': agents, 'description': '', @@ -86,3 +86,46 @@ def mock_activity_form(): } yield form +@pytest.fixture(scope='function') +def mock_activity_request(): + used = [ + { + 'name': 'Reference_3', + 'targetId': 'TargetID_3', + 'targetVersionId': '1.0', + 'class': 'Resource', + 'subclass': 'File' + }, + { + 'name': 'Reference_4', + 'target_id': 'TargetID_4', + 'target_version_id': '1.0', + '_class': 'Tool', + 'subclass': 'Tool' + } + ] + generated = [ + { + 'name': 'Reference_5', + 'targetId': 'TargetID_5', + 'targetVersionId': '1.0', + 'class': 'Resource', + 'subclass': 'State' + } + ] + agents = [ + { + 'name': 'User_1', + 'userId': 'UserID_1' + } + ] + form = { + 'name': 'Activity_3', + 'class': 'Tool session', + 'agents': agents, + 'description': '', + 'used': used, + 'generated': generated + + } + yield form diff --git a/synprov/test/test_activities_controller.py b/synprov/test/test_activities_controller.py deleted file mode 100644 index 9db0513..0000000 --- a/synprov/test/test_activities_controller.py +++ /dev/null @@ -1,72 +0,0 @@ -# # coding: utf-8 - -# from __future__ import absolute_import -# import unittest - -# from flask import json -# from six import BytesIO - -# from synprov.models import Activity # noqa: E501 -# from synprov.test import BaseTestCase - - -# class TestActivitiesController(BaseTestCase): -# """ActivitiesController integration test stubs""" - -# def test_create_activity(self): -# """Test case for create_activity - -# Create a new. -# """ -# body = { -# 'name': 'activity1', -# 'agents': [ -# {'agent_id': 'agent1'} -# ], -# 'used': [ -# { -# 'target_id': 'entity1', -# 'target_version_number': 1} -# ], -# 'generated': [ -# { -# 'target_id': 'entity2', -# 'target_version_number': 1 -# } -# ] -# } -# headers = { -# 'Accept': 'application/json', -# 'Content-Type': 'application/json', -# } -# response = self.client.open( -# '/rest/repo/v1/activity', -# method='POST', -# headers=headers, -# data=json.dumps(body), -# content_type='application/json') -# self.assert200(response, -# 'Response body is : ' + response.data.decode('utf-8')) - - -# def test_get_activity(self): -# """Test case for get_activity - -# Get an existing. -# """ -# headers = { -# 'Accept': 'application/json', -# 'Content-Type': 'application/json', -# } -# response = self.client.open( -# '/rest/repo/v1/activity/{id}'.format(id='id_example'), -# method='GET', -# headers=headers, -# content_type='application/json') -# self.assert200(response, -# 'Response body is : ' + response.data.decode('utf-8')) - - - -# if __name__ == '__main__': -# unittest.main() diff --git a/synprov/test/test_agents_controller.py b/synprov/test/test_agents_controller.py deleted file mode 100644 index 0207504..0000000 --- a/synprov/test/test_agents_controller.py +++ /dev/null @@ -1,18 +0,0 @@ -# # coding: utf-8 - -# from __future__ import absolute_import -# import unittest - -# from flask import json -# from six import BytesIO - -# from synprov.models import Agent # noqa: E501 -# from synprov.test import BaseTestCase - - -# class TestAgentsController(BaseTestCase): -# """AgentsController integration test stubs""" - - -# if __name__ == '__main__': -# unittest.main() diff --git a/synprov/test/test_controllers.py b/synprov/test/test_controllers.py new file mode 100644 index 0000000..77711fa --- /dev/null +++ b/synprov/test/test_controllers.py @@ -0,0 +1,47 @@ +import logging +import pytest + +from synprov.models import ActivityForm +from synprov.graph.controllers import activities_controller + + +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger(__name__) + + +class TestActivitiesController: + + def test_create_activity_exists(self, + mock_graph_data, + mock_activity_request): + node_count = len(mock_graph_data.nodes) + rel_count = len(mock_graph_data.relationships) + body = ActivityForm.from_dict(mock_activity_request) + act_node = activities_controller.create_activity(body) + assert len(mock_graph_data.nodes) == node_count + assert len(mock_graph_data.relationships) == rel_count + assert all([key in act_node for key in ['id', 'labels', 'properties']]) + + def test_create_activity_new(self, + mock_graph, + mock_activity_request): + node_count = len(mock_graph.nodes) + rel_count = len(mock_graph.relationships) + body = ActivityForm.from_dict(mock_activity_request) + act_node = activities_controller.create_activity(body) + + new_nodes = sum([ + len(mock_activity_request['used']), + len(mock_activity_request['generated']), + len(mock_activity_request['agents']), + 1 + ]) + new_rels = sum([ + len(mock_activity_request['used']), + len(mock_activity_request['generated']), + len(mock_activity_request['agents']) * 2, + ]) + + assert len(mock_graph.nodes) == (node_count + new_nodes) + assert len(mock_graph.relationships) == (rel_count + new_rels) + assert all([key in act_node for key in ['id', 'labels', 'properties']]) diff --git a/synprov/test/test_graphmodels.py b/synprov/test/test_models.py similarity index 100% rename from synprov/test/test_graphmodels.py rename to synprov/test/test_models.py diff --git a/synprov/test/test_references_controller.py b/synprov/test/test_references_controller.py deleted file mode 100644 index 4428687..0000000 --- a/synprov/test/test_references_controller.py +++ /dev/null @@ -1,18 +0,0 @@ -# # coding: utf-8 - -# from __future__ import absolute_import -# import unittest - -# from flask import json -# from six import BytesIO - -# from synprov.models import Reference # noqa: E501 -# from synprov.test import BaseTestCase - - -# class TestReferencesController(BaseTestCase): -# """ReferencesController integration test stubs""" - - -# if __name__ == '__main__': -# unittest.main() diff --git a/synprov/util.py b/synprov/util.py index 9702ecf..4809ec0 100644 --- a/synprov/util.py +++ b/synprov/util.py @@ -8,9 +8,6 @@ import typing import socket - -from datetime import datetime - from functools import wraps from hashlib import sha256 @@ -174,19 +171,9 @@ def _convert_keys(obj): return obj -def neo4j_to_d3(results): - nodes = [] - rels = [] - for record in results: - nodes.append(_convert_node(record['source'])) - nodes.append(_convert_node(record['target'])) - rels.append(_convert_relationship(record['relationship'])) - return {"nodes": nodes, "links": rels} - - def get_datetime(now=None): if now is None: - now = datetime.now() + now = datetime.datetime.now() _date_obj = iso8601.parse_date(now.isoformat()) _date_utc = _date_obj.astimezone(pytz.utc) return _date_utc.strftime('%Y-%m-%dT%H:%M:%SZ')