Skip to content

Commit a100fa9

Browse files
committed
Added OpenAPI validation to tests
We now generate and validate OpenAPI descriptions in both test_openapi and test_td
1 parent bfc6fc4 commit a100fa9

File tree

2 files changed

+47
-17
lines changed

2 files changed

+47
-17
lines changed

tests/test_openapi.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
1+
"""Test OpenAPI spec generation
2+
3+
This file tests the OpenAPI spec generated by LabThings.
4+
NB in order to avoid duplicating the examples, OpenAPI spec validation is also
5+
done in test_td.py.
6+
"""
7+
18
import pytest
29

310
from labthings import fields, schema
411
from labthings.actions.thread import ActionThread
512
from labthings.extensions import BaseExtension
613
from labthings.views import ActionView, PropertyView, EventView
714
from marshmallow import validate
15+
from apispec.utils import validate_spec
816

9-
def test_openapi(thing, action_view_cls):
10-
action_view_cls.args = {"n": fields.Integer()}
11-
thing.add_view(action_view_cls, "TestAction")
17+
def test_openapi(thing):
18+
"""Make an example Thing and check its openapi description validates"""
19+
class TestAction(ActionView):
20+
args = {"n": fields.Integer()}
21+
def post(self):
22+
return "POST"
23+
thing.add_view(TestAction, "TestAction")
1224

1325
class TestProperty(PropertyView):
1426
schema = {"count": fields.Integer()}
@@ -27,4 +39,5 @@ def post(self, args):
2739
thing.add_view(TestFieldProperty, "TestFieldProperty")
2840

2941

30-
thing.spec.to_yaml()
42+
thing.spec.to_yaml()
43+
validate_spec(thing.spec)

tests/test_td.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
from labthings import fields
44
from labthings.views import ActionView, PropertyView, View, op
5+
from apispec.utils import validate_spec
56

67

78
@pytest.fixture
89
def thing_description(thing):
910
return thing.thing_description
1011

1112

12-
def test_td_init(helpers, thing_description, app_ctx, schemas_path):
13+
def test_td_init(helpers, thing, thing_description, app_ctx, schemas_path):
1314
assert thing_description
1415
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
16+
validate_spec(thing.spec)
1517

1618

17-
def test_td_add_link(helpers, thing_description, view_cls, app_ctx, schemas_path):
19+
def test_td_add_link(helpers, thing, thing_description, view_cls, app_ctx, schemas_path):
20+
thing.add_view(view_cls, "/test_view_cls")
1821
thing_description.add_link(view_cls, "rel")
1922
assert {
2023
"rel": "rel",
@@ -24,9 +27,10 @@ def test_td_add_link(helpers, thing_description, view_cls, app_ctx, schemas_path
2427
} in thing_description._links
2528

2629
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
30+
validate_spec(thing.spec)
2731

2832

29-
def test_td_add_link_options(thing_description, view_cls):
33+
def test_td_add_link_options(thing, thing_description, view_cls):
3034
thing_description.add_link(
3135
view_cls, "rel", kwargs={"kwarg": "kvalue"}, params={"param": "pvalue"}
3236
)
@@ -36,9 +40,10 @@ def test_td_add_link_options(thing_description, view_cls):
3640
"params": {"param": "pvalue"},
3741
"kwargs": {"kwarg": "kvalue"},
3842
} in thing_description._links
43+
validate_spec(thing.spec)
3944

4045

41-
def test_td_links(thing_description, app_ctx, view_cls):
46+
def test_td_links(thing, thing_description, app_ctx, view_cls):
4247
thing_description.add_link(
4348
view_cls, "rel", kwargs={"kwarg": "kvalue"}, params={"param": "pvalue"}
4449
)
@@ -47,9 +52,10 @@ def test_td_links(thing_description, app_ctx, view_cls):
4752
assert {"rel": "rel", "href": "", "kwarg": "kvalue"} in (
4853
thing_description.links
4954
)
55+
validate_spec(thing.spec)
5056

5157

52-
def test_td_action(helpers, app, thing_description, app_ctx, schemas_path):
58+
def test_td_action(helpers, thing, app, thing_description, app_ctx, schemas_path):
5359
class Index(ActionView):
5460
def post(self):
5561
return "POST"
@@ -62,9 +68,10 @@ def post(self):
6268
with app_ctx.test_request_context():
6369
assert "index" in thing_description.to_dict().get("actions")
6470
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
71+
validate_spec(thing.spec)
6572

6673

67-
def test_td_action_with_schema(helpers, app, thing_description, app_ctx, schemas_path):
74+
def test_td_action_with_schema(helpers, thing, app, thing_description, app_ctx, schemas_path):
6875
class Index(ActionView):
6976
args = {"integer": fields.Int()}
7077
semtype = "ToggleAction"
@@ -80,9 +87,11 @@ def post(self):
8087
with app_ctx.test_request_context():
8188
assert "index" in thing_description.to_dict().get("actions")
8289
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
90+
91+
validate_spec(thing.spec)
8392

8493

85-
def test_td_property(helpers, app, thing_description, app_ctx, schemas_path):
94+
def test_td_property(helpers, app, thing, thing_description, app_ctx, schemas_path):
8695
class Index(PropertyView):
8796
def get(self):
8897
return "GET"
@@ -95,10 +104,11 @@ def get(self):
95104
with app_ctx.test_request_context():
96105
assert "index" in thing_description.to_dict().get("properties")
97106
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
107+
validate_spec(thing.spec)
98108

99109

100110
def test_td_property_with_schema(
101-
helpers, app, thing_description, app_ctx, schemas_path
111+
helpers, app, thing, thing_description, app_ctx, schemas_path
102112
):
103113
class Index(PropertyView):
104114
schema = fields.Int(required=True)
@@ -114,10 +124,11 @@ def get(self):
114124
with app_ctx.test_request_context():
115125
assert "index" in thing_description.to_dict().get("properties")
116126
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
127+
validate_spec(thing.spec)
117128

118129

119130
def test_td_property_with_url_param(
120-
helpers, app, thing_description, app_ctx, schemas_path
131+
helpers, app, thing, thing_description, app_ctx, schemas_path
121132
):
122133
class Index(PropertyView):
123134
def get(self):
@@ -131,9 +142,10 @@ def get(self):
131142
with app_ctx.test_request_context():
132143
assert "index" in thing_description.to_dict().get("properties")
133144
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
145+
validate_spec(thing.spec)
134146

135147

136-
def test_td_property_write_only(helpers, app, thing_description, app_ctx, schemas_path):
148+
def test_td_property_write_only(helpers, app, thing, thing_description, app_ctx, schemas_path):
137149
class Index(PropertyView):
138150
schema = fields.Int()
139151

@@ -148,10 +160,12 @@ def put(self):
148160
with app_ctx.test_request_context():
149161
assert "index" in thing_description.to_dict().get("properties")
150162
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
163+
164+
validate_spec(thing.spec)
151165

152166

153167
def test_td_property_post_to_write(
154-
helpers, app, thing_description, app_ctx, schemas_path
168+
helpers, app, thing, thing_description, app_ctx, schemas_path
155169
):
156170
class Index(PropertyView):
157171
@op.writeproperty
@@ -177,10 +191,11 @@ def post(self):
177191
== "POST"
178192
)
179193
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
194+
validate_spec(thing.spec)
180195

181196

182197
def test_td_property_different_content_type(
183-
helpers, app, thing_description, app_ctx, schemas_path
198+
helpers, app, thing, thing_description, app_ctx, schemas_path
184199
):
185200
class Index(PropertyView):
186201
content_type = "text/plain; charset=us-ascii"
@@ -198,10 +213,11 @@ def put(self):
198213
for form in thing_description.to_dict()["properties"]["index"]["forms"]:
199214
assert form["contentType"] == "text/plain; charset=us-ascii"
200215
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
216+
validate_spec(thing.spec)
201217

202218

203219
def test_td_action_different_response_type(
204-
helpers, app, thing_description, app_ctx, schemas_path
220+
helpers, app, thing, thing_description, app_ctx, schemas_path
205221
):
206222
class Index(ActionView):
207223
schema = fields.Int()
@@ -220,3 +236,4 @@ def post(self):
220236
for form in thing_description.to_dict()["actions"]["index"]["forms"]:
221237
assert form["response"]["contentType"] == "text/plain; charset=us-ascii"
222238
helpers.validate_thing_description(thing_description, app_ctx, schemas_path)
239+
validate_spec(thing.spec)

0 commit comments

Comments
 (0)