tests.test_todo_api   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 294
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 228
dl 0
loc 294
rs 10
c 0
b 0
f 0
wmc 13

10 Methods

Rating   Name   Duplication   Size   Complexity  
B TestTokenAPI.test_todos() 0 75 2
A TestTokenAPI.test_password_auth() 0 12 1
B TestTokenAPI.test_pagination() 0 74 1
A TestTokenAPI.test_cache_control() 0 10 1
A TestTokenAPI.setUp() 0 10 1
A TestTokenAPI.tearDown() 0 4 1
A TestTokenAPI.test_bad_auth() 0 9 1
A TestTokenAPI.test_rate_limits() 0 14 2
B TestTokenAPI.test_etag() 0 59 1
A TestTokenAPI.test_helpers() 0 4 2
1
import unittest
2
from werkzeug.exceptions import BadRequest
3
from .test_client import TestClient
4
from api.app import create_app
5
from api.models import db, User
6
from api.errors import ValidationError
7
from api.helpers import convert_url
8
9
10
class TestTokenAPI(unittest.TestCase):
11
  default_username = 'mamad'
12
  default_password = 'jafar'
13
14
  def setUp(self):
15
    self.app = create_app('test_config')
16
    self.ctx = self.app.app_context()
17
    self.ctx.push()
18
    db.drop_all()
19
    db.create_all()
20
    u = User(username=self.default_username, password=self.default_password)
21
    db.session.add(u)
22
    db.session.commit()
23
    self.client = TestClient(self.app, u.generate_auth_token(), '')
24
25
  def tearDown(self):
26
    db.session.remove()
27
    db.drop_all()
28
    self.ctx.pop()
29
30
  def test_password_auth(self):
31
    self.app.config['USE_TOKEN_AUTH'] = False
32
    good_client = TestClient(self.app, self.default_username,
33
                             self.default_password)
34
    rv, _ = good_client.get('/api/v1.0/todos/')
35
    self.assertTrue(rv.status_code == 200)
36
37
    self.app.config['USE_TOKEN_AUTH'] = True
38
    u = User.query.get(1)
39
    good_client = TestClient(self.app, u.generate_auth_token(), '')
40
    rv, json = good_client.get('/api/v1.0/todos/')
41
    self.assertTrue(rv.status_code == 200)
42
43
  def test_bad_auth(self):
44
    bad_client = TestClient(self.app, 'abc', 'def')
45
    rv, _ = bad_client.get('/api/v1.0/todos/')
46
    self.assertTrue(rv.status_code == 401)
47
48
    self.app.config['USE_TOKEN_AUTH'] = True
49
    bad_client = TestClient(self.app, 'bad_token', '')
50
    rv, json = bad_client.get('/api/v1.0/todos/')
51
    self.assertTrue(rv.status_code == 401)
52
53
  def test_rate_limits(self):
54
    self.app.config['USE_RATE_LIMITS'] = True
55
56
    rv, _ = self.client.get('/api/v1.0/todos/')
57
    self.assertTrue(rv.status_code == 200)
58
    self.assertTrue('X-RateLimit-Remaining' in rv.headers)
59
    self.assertTrue('X-RateLimit-Limit' in rv.headers)
60
    self.assertTrue('X-RateLimit-Reset' in rv.headers)
61
    self.assertTrue(
62
        int(rv.headers['X-RateLimit-Limit']) ==
63
        int(rv.headers['X-RateLimit-Remaining']) + 1)
64
    while int(rv.headers['X-RateLimit-Remaining']) > 0:
65
      rv, json = self.client.get('/api/v1.0/todos/')
66
    self.assertTrue(rv.status_code == 429)
67
68
  def test_pagination(self):
69
    # create several students
70
    rv, json = self.client.post(
71
        '/api/v1.0/todos/', data={
72
            'name': 'one',
73
            'task': 'sth'
74
        })
75
    self.assertTrue(rv.status_code == 201)
76
    one_url = rv.headers['Location']
77
    rv, json = self.client.post(
78
        '/api/v1.0/todos/', data={
79
            'name': 'two',
80
            'task': 'sth'
81
        })
82
    self.assertTrue(rv.status_code == 201)
83
    two_url = rv.headers['Location']
84
    rv, json = self.client.post(
85
        '/api/v1.0/todos/', data={
86
            'name': 'three',
87
            'task': 'sth'
88
        })
89
    self.assertTrue(rv.status_code == 201)
90
    three_url = rv.headers['Location']
91
    rv, json = self.client.post(
92
        '/api/v1.0/todos/', data={
93
            'name': 'four',
94
            'task': 'sth'
95
        })
96
    self.assertTrue(rv.status_code == 201)
97
    four_url = rv.headers['Location']
98
    rv, json = self.client.post(
99
        '/api/v1.0/todos/', data={
100
            'name': 'five',
101
            'task': 'sth'
102
        })
103
    self.assertTrue(rv.status_code == 201)
104
    five_url = rv.headers['Location']
105
106
    # get collection in pages
107
    rv, json = self.client.get('/api/v1.0/todos/?page=1&per_page=2')
108
    self.assertTrue(rv.status_code == 200)
109
    self.assertTrue(one_url in json['urls'])
110
    self.assertTrue(two_url in json['urls'])
111
    self.assertTrue(len(json['urls']) == 2)
112
    self.assertTrue('total' in json['meta'])
113
    self.assertTrue(json['meta']['total'] == 5)
114
    self.assertTrue('prev' in json['meta'])
115
    self.assertTrue(json['meta']['prev'] is None)
116
    first_url = json['meta']['first'].replace('http://localhost', '')
117
    last_url = json['meta']['last'].replace('http://localhost', '')
118
    next_url = json['meta']['next'].replace('http://localhost', '')
119
120
    rv, json = self.client.get(first_url)
121
    self.assertTrue(rv.status_code == 200)
122
    self.assertTrue(one_url in json['urls'])
123
    self.assertTrue(two_url in json['urls'])
124
    self.assertTrue(len(json['urls']) == 2)
125
126
    rv, json = self.client.get(next_url)
127
    self.assertTrue(rv.status_code == 200)
128
    self.assertTrue(three_url in json['urls'])
129
    self.assertTrue(four_url in json['urls'])
130
    self.assertTrue(len(json['urls']) == 2)
131
    next_url = json['meta']['next'].replace('http://localhost', '')
132
133
    rv, json = self.client.get(next_url)
134
    self.assertTrue(rv.status_code == 200)
135
    self.assertTrue(five_url in json['urls'])
136
    self.assertTrue(len(json['urls']) == 1)
137
138
    rv, json = self.client.get(last_url)
139
    self.assertTrue(rv.status_code == 200)
140
    self.assertTrue(five_url in json['urls'])
141
    self.assertTrue(len(json['urls']) == 1)
142
143
  def test_cache_control(self):
144
    client = TestClient(self.app, self.default_username, self.default_password)
145
    rv, json = client.get('/auth/request-token')
146
    self.assertTrue(rv.status_code == 200)
147
    self.assertTrue('Cache-Control' in rv.headers)
148
    cache = [c.strip() for c in rv.headers['Cache-Control'].split(',')]
149
    self.assertTrue('no-cache' in cache)
150
    self.assertTrue('no-store' in cache)
151
    self.assertTrue('max-age=0' in cache)
152
    self.assertTrue(len(cache) == 3)
153
154
  def test_etag(self):
155
    # create two todos
156
    rv, _ = self.client.post(
157
        '/api/v1.0/todos/', data={
158
            'name': 'one',
159
            'task': 'sth'
160
        })
161
    self.assertTrue(rv.status_code == 201)
162
    one_url = rv.headers['Location']
163
    rv, json = self.client.post(
164
        '/api/v1.0/todos/', data={
165
            'name': 'two',
166
            'task': 'sth'
167
        })
168
    self.assertTrue(rv.status_code == 201)
169
    two_url = rv.headers['Location']
170
171
    # get their etags
172
    rv, json = self.client.get(one_url)
173
    self.assertTrue(rv.status_code == 200)
174
    one_etag = rv.headers['ETag']
175
    rv, json = self.client.get(two_url)
176
    self.assertTrue(rv.status_code == 200)
177
    two_etag = rv.headers['ETag']
178
179
    # send If-None-Match header
180
    rv, json = self.client.get(one_url, headers={'If-None-Match': one_etag})
181
    self.assertTrue(rv.status_code == 304)
182
    rv, json = self.client.get(
183
        one_url, headers={'If-None-Match': one_etag + ', ' + two_etag})
184
    self.assertTrue(rv.status_code == 304)
185
    rv, json = self.client.get(one_url, headers={'If-None-Match': two_etag})
186
    self.assertTrue(rv.status_code == 200)
187
    rv, json = self.client.get(
188
        one_url, headers={'If-None-Match': two_etag + ', *'})
189
    self.assertTrue(rv.status_code == 304)
190
191
    # send If-Match header
192
    rv, json = self.client.get(one_url, headers={'If-Match': one_etag})
193
    self.assertTrue(rv.status_code == 200)
194
    rv, json = self.client.get(
195
        one_url, headers={'If-Match': one_etag + ', ' + two_etag})
196
    self.assertTrue(rv.status_code == 200)
197
    rv, json = self.client.get(one_url, headers={'If-Match': two_etag})
198
    self.assertTrue(rv.status_code == 412)
199
    rv, json = self.client.get(one_url, headers={'If-Match': '*'})
200
    self.assertTrue(rv.status_code == 200)
201
202
    # change a resource
203
    rv, json = self.client.put(
204
        one_url, data={
205
            'name': 'not-one',
206
            'task': 'sth'
207
        })
208
    self.assertTrue(rv.status_code == 200)
209
210
    # use stale etag
211
    rv, json = self.client.get(one_url, headers={'If-None-Match': one_etag})
212
    self.assertTrue(rv.status_code == 200)
213
214
  def test_helpers(self):
215
    self.assertEqual(convert_url('www.google.com'), 'http://www.google.com')
216
    with self.assertRaises(ValidationError):
217
      convert_url('bad url')
218
219
  def test_todos(self):
220
    # get collection
221
    rv, json = self.client.get('/api/v1.0/todos/')
222
    self.assertTrue(rv.status_code == 200)
223
    self.assertTrue(json['urls'] == [])
224
225
    # create new
226
    rv, json = self.client.post(
227
        '/api/v1.0/todos/', data={
228
            'name': 'buy',
229
            'task': 'buy groceries'
230
        })
231
    self.assertTrue(rv.status_code == 201)
232
    buy_url = rv.headers['Location']
233
234
    # get
235
    rv, json = self.client.get(buy_url)
236
    self.assertTrue(rv.status_code == 200)
237
    self.assertTrue(json['name'] == 'buy')
238
    self.assertTrue(json['url'] == buy_url)
239
240
    # create new
241
    rv, json = self.client.post(
242
        '/api/v1.0/todos/',
243
        data={
244
            'name': 'clean',
245
            'task': 'clean dining room'
246
        })
247
    self.assertTrue(rv.status_code == 201)
248
    clean_url = rv.headers['Location']
249
250
    # get
251
    rv, json = self.client.get(clean_url)
252
    self.assertTrue(rv.status_code == 200)
253
    self.assertTrue(json['name'] == 'clean')
254
    self.assertTrue(json['url'] == clean_url)
255
256
    # create bad request
257
    rv, json = self.client.post('/api/v1.0/todos/', data={})
258
    self.assertTrue(rv.status_code == 400)
259
260
    self.assertRaises(ValidationError, lambda:
261
                      self.client.post('/api/v1.0/todos/',
262
                                       data={'not-name': 'clean'}))
263
264
    # modify
265
    rv, json = self.client.put(
266
        clean_url, data={
267
            'name': 'clean',
268
            'task': 'clean bathroom'
269
        })
270
    self.assertTrue(rv.status_code == 200)
271
272
    # get
273
    rv, json = self.client.get(clean_url)
274
    self.assertTrue(rv.status_code == 200)
275
    self.assertTrue(json['task'] == 'clean bathroom')
276
277
    # get collection
278
    rv, json = self.client.get('/api/v1.0/todos/')
279
    self.assertTrue(rv.status_code == 200)
280
    self.assertTrue(buy_url in json['urls'])
281
    self.assertTrue(clean_url in json['urls'])
282
    self.assertTrue(len(json['urls']) == 2)
283
284
    # delete
285
    rv, json = self.client.delete(buy_url)
286
    self.assertTrue(rv.status_code == 200)
287
288
    # get collection
289
    rv, json = self.client.get('/api/v1.0/todos/')
290
    self.assertTrue(rv.status_code == 200)
291
    self.assertFalse(buy_url in json['urls'])
292
    self.assertTrue(clean_url in json['urls'])
293
    self.assertTrue(len(json['urls']) == 1)
294