test_blueprints.py 8.26 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
77
78
79
80
81
82
83
        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',
                                               '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
84

J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
85
86
    def test_analysis_extra(self):
        """
87
        Extra params that have a default should use it
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
88
        """
89
        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
90
91
92
93
94
95
96
97
98
99
100
        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
101
        self.app.config['TESTING'] = False  # Errors are expected in this case
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
102
103
104
105
106
        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
107
108
109
110
        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
111

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
    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'

150
151
152
153
154
    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
155
        self.app.config['TESTING'] = False  # Errors are expected in this case
156
157
158
159
160
161
        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)

162
163
    def test_list(self):
        """ List the plugins """
Ignacio Corcuera's avatar
Ignacio Corcuera committed
164
        resp = self.client.get("/api/plugins/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
165
166
167
168
169
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        logging.debug(js)
        assert 'plugins' in js
        plugins = js['plugins']
170
171
        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
172
        assert "@context" in js
173
174

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

    def test_detail(self):
        """ Show only one plugin"""
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
192
        resp = self.client.get("/api/plugins/Dummy/")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
193
194
195
196
        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
197
        assert js["@id"] == "endpoint:plugins/Dummy_0.1"
198

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

    def test_context(self):
        resp = self.client.get("/api/contexts/context.jsonld")
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
210
211
212
        self.assertCode(resp, 200)
        js = parse_resp(resp)
        assert "@context" in js
213
        assert check_dict(
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
214
            js["@context"],
215
216
217
218
            {"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
219
        self.assertCode(resp, 200)
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
220
        assert "$schema" in resp.data.decode()
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
221
222
223
224
225

    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
226
227
        assert "valid_parameters" in js
        assert "help" in js["valid_parameters"]
J. Fernando Sánchez's avatar
J. Fernando Sánchez committed
228
229

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