test_blueprints.py 8.33 KB
Newer Older
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
1
2
import os
import logging
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
3

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
4
from senpy.extensions import Senpy
5
from senpy import models
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
6
from flask import Flask
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
7
from unittest import TestCase
8
from itertools import product
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
9

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
10

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
11
def check_dict(indic, template):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
12
    return all(item in indic.items() for item in template.items())
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
13

J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
14

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
15
def parse_resp(resp):
16
    return models.from_json(resp.data.decode('utf-8'))
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
17

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
18
19

class BlueprintsTest(TestCase):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
20
21
22
23
24
    @classmethod
    def setUpClass(cls):
        """Set up only once, and re-use in every individual test"""
        cls.app = Flask("test_extensions")
        cls.client = cls.app.test_client()
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
25
        cls.senpy = Senpy(default_plugins=True)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
26
27
28
29
30
31
        cls.senpy.init_app(cls.app)
        cls.dir = os.path.join(os.path.dirname(__file__), "..")
        cls.senpy.add_folder(cls.dir)
        cls.senpy.activate_plugin("Dummy", sync=True)
        cls.senpy.activate_plugin("DummyRequired", sync=True)
        cls.senpy.default_plugin = 'Dummy'
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
32

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
33
34
35
    def setUp(self):
        self.app.config['TESTING'] = True  # Tell Flask not to catch Exceptions

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
36
37
    def assertCode(self, resp, code):
        self.assertEqual(resp.status_code, code)
J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
38

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
39
40
    def test_playground(self):
        resp = self.client.get("/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
41
        assert "main.js" in resp.get_data(as_text=True)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
42

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
43
    def test_home(self):
44
45
46
        """
        Calling with no arguments should ask the user for more arguments
        """
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
47
        self.app.config['TESTING'] = False  # Errors are expected in this case
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
48
        resp = self.client.get("/api/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
49
        self.assertCode(resp, 400)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
50
51
        js = parse_resp(resp)
        logging.debug(js)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
52
        assert js["status"] == 400
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
53
        atleast = {
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
54
            "status": 400,
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
55
56
            "message": "Missing or invalid parameters",
        }
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
57
        assert check_dict(js, atleast)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
58

59
    def test_analysis(self):
60
61
62
63
        """
        The dummy plugin returns an empty response,\
        it should contain the context
        """
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
64
        resp = self.client.get("/api/?i=My aloha mohame&with_parameters=True")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
65
66
67
68
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug("Got response: %s", js)
        assert "@context" in js
J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
69
        assert "entries" in js
70
71
72
73
74
75
76
        assert len(js['analysis']) == 1

    def test_analysis_post(self):
        """
        The results for a POST request should be the same as for a GET request.
        """
        resp = self.client.post("/api/", data={'i': 'My aloha mohame',
77
                                               'algorithm': 'rand',
78
79
80
81
82
83
84
                                               'with_parameters': True})
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug("Got response: %s", js)
        assert "@context" in js
        assert "entries" in js
        assert len(js['analysis']) == 1
85

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
86
87
    def test_analysis_extra(self):
        """
88
        Extra params that have a default should use it
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
89
        """
90
        resp = self.client.get("/api/?i=My aloha mohame&algo=Dummy&with_parameters=true")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
91
92
93
94
95
96
97
98
99
100
101
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug("Got response: %s", js)
        assert "@context" in js
        assert "entries" in js

    def test_analysis_extra_required(self):
        """
        Extra params that have a required argument that does not
        have a default should raise an error.
        """
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
102
        self.app.config['TESTING'] = False  # Errors are expected in this case
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
103
104
105
106
107
        resp = self.client.get("/api/?i=My aloha mohame&algo=DummyRequired")
        self.assertCode(resp, 400)
        js = parse_resp(resp)
        logging.debug("Got response: %s", js)
        assert isinstance(js, models.Error)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
108
109
110
111
        resp = self.client.get("/api/?i=My aloha mohame&algo=DummyRequired&example=notvalid")
        self.assertCode(resp, 400)
        resp = self.client.get("/api/?i=My aloha mohame&algo=DummyRequired&example=a")
        self.assertCode(resp, 200)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
112

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    def test_analysis_url(self):
        """
        The algorithm can also be specified as part of the URL
        """
        self.app.config['TESTING'] = False  # Errors are expected in this case
        resp = self.client.get("/api/DummyRequired?i=My aloha mohame")
        self.assertCode(resp, 400)
        js = parse_resp(resp)
        logging.debug("Got response: %s", js)
        assert isinstance(js, models.Error)
        resp = self.client.get("/api/DummyRequired?i=My aloha mohame&example=notvalid")
        self.assertCode(resp, 400)
        resp = self.client.get("/api/DummyRequired?i=My aloha mohame&example=a")
        self.assertCode(resp, 200)

    def test_analysis_chain(self):
        """
        More than one algorithm can be specified. Plugins will then be chained
        """
        resp = self.client.get("/api/Dummy?i=My aloha mohame")
        js = parse_resp(resp)
        assert len(js['analysis']) == 1
        assert js['entries'][0]['nif:isString'] == 'My aloha mohame'[::-1]

        resp = self.client.get("/api/Dummy/Dummy?i=My aloha mohame")
        # Calling dummy twice, should return the same string
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        assert len(js['analysis']) == 2
        assert js['entries'][0]['nif:isString'] == 'My aloha mohame'

        resp = self.client.get("/api/Dummy+Dummy?i=My aloha mohame")
        # Same with pluses instead of slashes
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        assert len(js['analysis']) == 2
        assert js['entries'][0]['nif:isString'] == 'My aloha mohame'

151
152
153
154
155
    def test_error(self):
        """
        The dummy plugin returns an empty response,\
        it should contain the context
        """
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
156
        self.app.config['TESTING'] = False  # Errors are expected in this case
157
158
159
160
161
162
        resp = self.client.get("/api/?i=My aloha mohame&algo=DOESNOTEXIST")
        self.assertCode(resp, 404)
        js = parse_resp(resp)
        logging.debug("Got response: %s", js)
        assert isinstance(js, models.Error)

163
164
    def test_list(self):
        """ List the plugins """
Ignacio Corcuera's avatar
Ignacio Corcuera committed
165
        resp = self.client.get("/api/plugins/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
166
167
168
169
170
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug(js)
        assert 'plugins' in js
        plugins = js['plugins']
171
172
        assert len(plugins) > 1
        assert list(p for p in plugins if p['name'] == "Dummy")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
173
        assert "@context" in js
174
175

    def test_headers(self):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
176
        for i, j in product(["/api/plugins/?nothing=", "/api/?i=test&"],
177
                            ["inHeaders"]):
Ignacio Corcuera's avatar
Ignacio Corcuera committed
178
            resp = self.client.get("%s" % (i))
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
179
180
            js = parse_resp(resp)
            assert "@context" in js
Ignacio Corcuera's avatar
Ignacio Corcuera committed
181
            resp = self.client.get("%s&%s=0" % (i, j))
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
182
            js = parse_resp(resp)
J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
183
            assert "@context" in js
Ignacio Corcuera's avatar
Ignacio Corcuera committed
184
            resp = self.client.get("%s&%s=1" % (i, j))
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
185
            js = parse_resp(resp)
J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
186
            assert "@context" not in js
Ignacio Corcuera's avatar
Ignacio Corcuera committed
187
            resp = self.client.get("%s&%s=true" % (i, j))
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
188
            js = parse_resp(resp)
J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
189
            assert "@context" not in js
190
191
192

    def test_detail(self):
        """ Show only one plugin"""
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
193
        resp = self.client.get("/api/plugins/Dummy/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
194
195
196
197
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug(js)
        assert "@id" in js
J. Fernando Sánchez's avatar
WIP    
J. Fernando Sánchez committed
198
        assert js["@id"] == "endpoint:plugins/Dummy_0.1"
199

200
201
    def test_default(self):
        """ Show only one plugin"""
202
        resp = self.client.get("/api/plugins/default/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
203
204
205
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug(js)
J. Fernando Sánchez's avatar
YAPFed    
J. Fernando Sánchez committed
206
        assert "@id" in js
J. Fernando Sánchez's avatar
WIP    
J. Fernando Sánchez committed
207
        assert js["@id"] == "endpoint:plugins/Dummy_0.1"
208
209
210

    def test_context(self):
        resp = self.client.get("/api/contexts/context.jsonld")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
211
212
213
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        assert "@context" in js
214
        assert check_dict(
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
215
            js["@context"],
216
217
218
219
            {"marl": "http://www.gsi.dit.upm.es/ontologies/marl/ns#"})

    def test_schema(self):
        resp = self.client.get("/api/schemas/definitions.json")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
220
        self.assertCode(resp, 200)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
221
        assert "$schema" in resp.data.decode()
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
222
223
224
225
226

    def test_help(self):
        resp = self.client.get("/api/?help=true")
        self.assertCode(resp, 200)
        js = parse_resp(resp)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
227
228
        assert "valid_parameters" in js
        assert "help" in js["valid_parameters"]
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
229
230

    def test_conversion(self):
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
231
        self.app.config['TESTING'] = False  # Errors are expected in this case
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
232
233
        resp = self.client.get("/api/?input=hello&algo=emoRand&emotionModel=DOES NOT EXIST")
        self.assertCode(resp, 404)