Skip to content

Commit 54d5df9

Browse files
committed
Added some more tests of thing description
After the changes I made to action schemas, I wanted to ensure I'd not broken the Thing Description. I am no longer worried - the TD serialises schemas in place and doesn't rely on names. The thing that mostly went wrong was naming the schemas, which doesn't apply to the TD. Also, I've tested all the cases I can think of, and the TD still validates.
1 parent af6a8d3 commit 54d5df9

File tree

4 files changed

+62
-42
lines changed

4 files changed

+62
-42
lines changed

src/labthings/schema.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,21 @@ def build_action_schema(
156156
name: Optional[str] = None,
157157
base_class: type = ActionSchema,
158158
):
159-
"""Builds a complete schema for a given ActionView. That is, it reads any input and output
160-
schemas attached to the POST method, and nests them within the input/output fields of
161-
the generic ActionSchema.
159+
"""Builds a complete schema for a given ActionView.
160+
161+
This method combines input and output schemas for a particular
162+
Action with the generic ActionSchema to give a specific ActionSchema
163+
subclass for that Action.
164+
165+
This is used in the Thing Description (where it is serialised to
166+
JSON in-place) but not in the OpenAPI description (where the input,
167+
output, and ActionSchema schemas are combined using `allOf`.)
162168
163169
:param output_schema: Schema:
164170
:param input_schema: Schema:
165171
:param name: str: (Default value = None)
166172
167173
"""
168-
# FIXME: this seems to lose the schemas. I suspect this is down to `nest_if_needed`.
169174
# Create a name for the generated schema
170175
if not name:
171176
name = str(id(output_schema))

tests/conftest.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
from flask import Flask
99
from flask.testing import FlaskClient
1010
from flask.views import MethodView
11+
from marshmallow import validate
1112

12-
from labthings import LabThing
13+
from labthings import LabThing, fields
1314
from labthings.actions import Pool
1415
from labthings.json import encode_json
1516
from labthings.views import ActionView, PropertyView, View
@@ -179,6 +180,41 @@ def thing_ctx(thing):
179180
yield thing.app
180181

181182

183+
@pytest.fixture
184+
def thing_with_some_views(thing):
185+
class TestAction(ActionView):
186+
args = {"n": fields.Integer()}
187+
188+
def post(self):
189+
return "POST"
190+
191+
thing.add_view(TestAction, "TestAction")
192+
193+
class TestProperty(PropertyView):
194+
schema = {"count": fields.Integer()}
195+
196+
def get(self):
197+
return 1
198+
199+
def post(self, args):
200+
pass
201+
202+
thing.add_view(TestProperty, "TestProperty")
203+
204+
class TestFieldProperty(PropertyView):
205+
schema = fields.String(validate=validate.OneOf(["one", "two"]))
206+
207+
def get(self):
208+
return "one"
209+
210+
def post(self, args):
211+
pass
212+
213+
thing.add_view(TestFieldProperty, "TestFieldProperty")
214+
215+
return thing
216+
217+
182218
@pytest.fixture()
183219
def debug_app(request):
184220

tests/test_openapi.py

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import yaml
1111
from apispec.ext.marshmallow import MarshmallowPlugin
1212
from apispec.utils import validate_spec
13-
from marshmallow import validate
1413

1514
from labthings import fields, schema
1615
from labthings.actions.thread import ActionThread
@@ -21,41 +20,6 @@
2120
from labthings.utilities import get_by_path
2221

2322

24-
@pytest.fixture
25-
def thing_with_some_views(thing):
26-
class TestAction(ActionView):
27-
args = {"n": fields.Integer()}
28-
29-
def post(self):
30-
return "POST"
31-
32-
thing.add_view(TestAction, "TestAction")
33-
34-
class TestProperty(PropertyView):
35-
schema = {"count": fields.Integer()}
36-
37-
def get(self):
38-
return 1
39-
40-
def post(self, args):
41-
pass
42-
43-
thing.add_view(TestProperty, "TestProperty")
44-
45-
class TestFieldProperty(PropertyView):
46-
schema = fields.String(validate=validate.OneOf(["one", "two"]))
47-
48-
def get(self):
49-
return "one"
50-
51-
def post(self, args):
52-
pass
53-
54-
thing.add_view(TestFieldProperty, "TestFieldProperty")
55-
56-
return thing
57-
58-
5923
def test_openapi(thing_with_some_views):
6024
"""Make an example Thing and check its openapi description validates"""
6125

@@ -74,7 +38,12 @@ class TestAction(ActionView):
7438
def post(self):
7539
return "POST"
7640

77-
t.add_view(TestAction, "TestActionM", endpoint="TestActionM")
41+
with pytest.warns(UserWarning):
42+
t.add_view(TestAction, "TestActionM", endpoint="TestActionM")
43+
44+
for v in t._action_views.values():
45+
# We should have two actions with the same name
46+
assert v.__name__ == "TestAction"
7847

7948
api = t.spec.to_dict()
8049
original_input_schema = get_by_path(api, ["paths", "/TestAction", "post"])

tests/test_td.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ def test_td_init(helpers, thing, thing_description, app_ctx, schemas_path):
1616
validate_spec(thing.spec)
1717

1818

19+
def test_interesting_td(helpers, thing_with_some_views, app_ctx, schemas_path):
20+
td = thing_with_some_views.thing_description
21+
helpers.validate_thing_description(td, app_ctx, schemas_path)
22+
validate_spec(thing_with_some_views.spec)
23+
# Check the arguments were preserved OK for TestAction
24+
assert td.actions["TestAction"]["input"]["properties"] == {
25+
"n": {"type": "number", "format": "integer"}
26+
}
27+
28+
1929
def test_td_add_link(
2030
helpers, thing, thing_description, view_cls, app_ctx, schemas_path
2131
):

0 commit comments

Comments
 (0)