Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inversionSolution resolver for AutomationTask #224

Merged
merged 2 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions graphql_api/schema/custom/automation_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ class Meta:
model_type = ModelType()
task_type = TaskSubType()
inversion_solution = graphene.Field(
'graphql_api.schema.custom.inversion_solution.InversionSolution',
description="the primary result of this task (only for task_type == INVERSION.",
'graphql_api.schema.custom.inversion_solution_union.InversionSolutionUnion',
description="the result of this task. NB only available for task_types:"
"INVERSION, SCALE_SOLUTION, AGGREGATE_SOLUTION, TIME_DEPENDENT_SOLUTION.",
)

@staticmethod
Expand All @@ -56,16 +57,27 @@ def from_json(jsondata):

@staticmethod
def resolve_inversion_solution(root, info, **args):

log.info(f"resolve_inversion_solution {root.task_type}")
resolvable_types = [
TaskSubType.INVERSION.value,
TaskSubType.SCALE_SOLUTION.value,
TaskSubType.AGGREGATE_SOLUTION.value,
TaskSubType.TIME_DEPENDENT_SOLUTION.value,
]

if not len(root.files):
return
if not root.task_type == TaskSubType.INVERSION.value:
if root.task_type not in resolvable_types:
log.info(f"Cannot resove inversion_soluton for {root.task_type}")
return

t0 = dt.utcnow()
res = None

# TODO this is an ugly hack....
# - It gets the inversion solution by traversing the file_relations until it finds an InversionSolution.
# - It gets the inversion solution by traversing the file_relations until it finds
# an InversionSolution subtype.
# - Instead this attribute needs to be a first-class one-to-one relationship
for file_id in root.files:
if isinstance(file_id, dict): # new form, files is list of objects
Expand All @@ -79,9 +91,11 @@ def resolve_inversion_solution(root, info, **args):
if not file_relation.role == FileRole.WRITE.value:
continue
file = get_data_manager().file.get_one(file_relation.file_id)
if file.__class__.__name__ == 'InversionSolution':
if 'InversionSolution' in file.__class__.__name__:
res = file
log.info(f"resolved inversion_solution file {file}")
break

db_metrics.put_duration(__name__, 'AutomationTask.resolve_inversion_solution', dt.utcnow() - t0)
return res

Expand Down
17 changes: 17 additions & 0 deletions graphql_api/schema/custom/inversion_solution_union.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# !inversion_solution_union.py
import graphene

from .aggregate_inversion_solution import AggregateInversionSolution
from .inversion_solution import InversionSolution
from .scaled_inversion_solution import ScaledInversionSolution
from .time_dependent_inversion_solution import TimeDependentInversionSolution


class InversionSolutionUnion(graphene.Union):
class Meta:
types = (
InversionSolution,
ScaledInversionSolution,
AggregateInversionSolution,
TimeDependentInversionSolution,
)
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ def test_task_product_query(self, mocked_api_DB):
id
created
inversion_solution {
id
file_name
... on Node { id }
... on FileInterface { file_name }
}
files {
total_count
Expand Down Expand Up @@ -183,8 +183,8 @@ def test_example_failing_product_query(self, mocked_api_DB):
id
created
inversion_solution {
id
file_name
... on Node { id }
... on FileInterface { file_name }
}
files {
total_count
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ def test_task_product_query(self, mocked_api):
id
created
inversion_solution {
id
file_name
... on Node { id }
... on FileInterface { file_name }
}
files {
total_count
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
Test API function for GeneralTask
using moto mocking re issue #223
"""

import datetime as dt
import unittest

import boto3
from dateutil.tz import tzutc
from graphene.test import Client
from graphql_relay import from_global_id
from moto import mock_dynamodb, mock_s3
from pynamodb.connection.base import Connection # for mocking

from graphql_api.config import REGION, S3_BUCKET_NAME
from graphql_api.data import data_manager
from graphql_api.dynamodb.models import ToshiFileObject, ToshiIdentity, ToshiThingObject
from graphql_api.schema import root_schema
from graphql_api.schema.search_manager import SearchManager

from .hazard.setup_helpers import SetupHelpersMixin


@mock_dynamodb
@mock_s3
class TestScaledInversionSolution(unittest.TestCase, SetupHelpersMixin):
def setUp(self):
self.client = Client(root_schema)

# S3
self._s3 = boto3.resource('s3', region_name=REGION)
self._s3.create_bucket(Bucket=S3_BUCKET_NAME)

# Dynamo
self._connection = Connection(region=REGION)

ToshiThingObject.create_table()
ToshiFileObject.create_table()
ToshiIdentity.create_table()

self._data_manager = data_manager.DataManager(search_manager=SearchManager('test', 'test', {'fake': 'auth'}))

upstream_sid = self.create_source_solution()
self.new_gt = self.create_general_task()
self.at_id = self.create_automation_task("SCALE_SOLUTION")
self.create_gt_relation(self.new_gt, self.at_id)

result = self.create_scaled_solution(upstream_sid, self.at_id)

ss = result['data']['create_scaled_inversion_solution']['solution']
self.scaled_solution_id = ss['id']

# def create_task_file(self, task_id, file_id, role):
qry2 = '''
mutation create_file_relation(
$thing_id:ID!
$file_id:ID!
$role:FileRole!) {
create_file_relation(
file_id:$file_id
thing_id:$thing_id
role:$role
)
{
ok
}
}'''
variables = dict(thing_id=self.at_id, file_id=self.at_id, role='WRITE')
executed = self.client.execute(qry2, variable_values=variables)
print('created file relation', executed)

def test_general_task_query(self):
print("self.new_gt", self.new_gt)

qry = '''
query GeneralTaskChildrenTabQuery($id: ID!) {
node(id: $id) {
... on GeneralTask {
id
model_type
children {
edges {
node {
child {
__typename
... on Node {
id
}
...on AutomationTask {
task_type
inversion_solution {
__typename
... on Node {
id
}
}
}
... on AutomationTaskInterface {
state
result
created
duration
arguments {
k
v
}
}
}
}
}
}
}
}
}

'''

print(qry)
executed = self.client.execute(qry, variable_values=dict(id=self.new_gt))
print(executed)

node = executed['data']['node']
assert node['id'] == self.new_gt
assert node['children']['edges'][0]['node']['child']['__typename'] == "AutomationTask"
assert node['children']['edges'][0]['node']['child']['inversion_solution']['__typename']
assert node['children']['edges'][0]['node']['child']['inversion_solution']['id'] == self.scaled_solution_id
assert (
node['children']['edges'][0]['node']['child']['inversion_solution']['__typename']
== "ScaledInversionSolution"
)
20 changes: 12 additions & 8 deletions graphql_api/tests/test_inversion_solution_bug_93.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,19 @@ def test_query_with_files(self, mocked_read_object, mocked_get_one):
task_type
id
inversion_solution {
id
file_name
meta {
k
v
... on Node { id }
... on FileInterface {
file_name
meta {
k
v
}
}
tables {
table_id
table_type
... on InversionSolutionInterface {
tables {
table_id
table_type
}
}
}
}
Expand Down
Loading