1 from datetime import datetime
2 from tests.test_basics import BasicTest
5 # no specific rights required
6 class GeneralTests(BasicTest):
19 def test_main_page(self):
20 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
21 self.assertEqual(response.status_code, 200)
23 def test_basic_results_data(self):
24 result = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
25 testtext= '<div class="motion card" id="motion-3">\n <div class="motion-title card-heading alert-warning">'\
26 + '\n <span class="title-text">Motion C</span> (Canceled)\n <span class="motion-type">group1</span>'\
27 + '\n <div># g1.20200402.003'\
28 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.003" role="button">Result</a>'\
29 + '\n </div>\n <div class="date">'\
30 + '\n <div>Proposed: 2020-04-02 21:47:24 (UTC) by User A</div>'\
31 + '\n <div>Canceled: 2020-04-03 21:48:24 (UTC) by User A</div>\n </div>\n </div>'\
32 + '\n <div class="card-body">\n <p><p>A third motion</p></p>'\
33 + '\n <p>\nYes <span class="badge badge-pill badge-secondary">1</span><br>'\
34 + '\nNo <span class="badge badge-pill badge-secondary">0</span><br>'\
35 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>'\
36 + '\n <p>Cancelation reason: Entered with wrong text</p>\n </div>\n</div>\n'
37 self.assertIn(str.encode(testtext), result.data)
38 testtext= '<div class="motion card" id="motion-2">\n <div class="motion-title card-heading alert-danger">'\
39 + '\n <span class="title-text">Motion B</span> (Finished)\n <span class="motion-type">group1</span>'\
40 + '\n <div># g1.20200402.002'\
41 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.002" role="button">Result</a>'\
42 + '\n </div>\n <div class="date">\n <div>Proposed: 2020-04-02 21:41:26 (UTC) by User A</div>'\
43 + '\n <div>Votes until: 2020-04-04 21:41:26 (UTC)</div>\n </div>\n </div>'\
44 + '\n <div class="card-body">\n <p><p>A second motion</p></p>\n <p>'\
45 + '\nYes <span class="badge badge-pill badge-secondary">1</span><br>'\
46 + '\nNo <span class="badge badge-pill badge-secondary">2</span><br>'\
47 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>\n </div>\n</div>\n'
48 self.assertIn(str.encode(testtext), result.data)
49 testtext= '<div class="motion card" id="motion-1">\n <div class="motion-title card-heading alert-success">'\
50 + '\n <span class="title-text">Motion A</span> (Finished)\n <span class="motion-type">group1</span>'\
51 + '\n <div># g1.20200402.001'\
52 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.001" role="button">Result</a>'\
53 + '\n </div>\n <div class="date">\n <div>Proposed: 2020-04-02 21:40:33 (UTC) by User A</div>'\
54 + '\n <div>Votes until: 2020-04-02 21:40:33 (UTC)</div>\n </div>\n </div>'\
55 + '\n <div class="card-body">\n <p><p>My special motion</p></p>\n <p>'\
56 + '\nYes <span class="badge badge-pill badge-secondary">2</span><br>'\
57 + '\nNo <span class="badge badge-pill badge-secondary">1</span><br>'\
58 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>\n </div>\n</div>\n'
59 self.assertIn(str.encode(testtext), result.data)
60 testtext= 'Proxy management'
61 self.assertNotIn(str.encode(testtext), result.data)
63 # start with second motion
64 result = self.app.get('/', environ_base={'USER_ROLES': user}, query_string=dict(start=2))
65 testtext= 'id=\"motion-3\">'
66 self.assertNotIn(str.encode(testtext), result.data)
67 testtext= 'id=\"motion-2">'
68 self.assertIn(str.encode(testtext), result.data)
69 testtext= 'id=\"motion-1\">'
70 self.assertIn(str.encode(testtext), result.data)
72 def test_basic_results_data_details(self):
73 motion='g1.20200402.002'
74 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
75 testtext= '<p>A second motion</p></p>\n </div>\n</div>\n<a href=\"/?start=2#motion-2\" class=\"btn btn-primary\">Back</a>'
76 self.assertIn(str.encode(testtext), result.data)
79 motion='g1.20200402.004'
80 response = self.createVote(user, motion, 'yes', userid)
81 self.assertEqual(response.status_code, 403)
82 self.assertIn(str.encode('Forbidden'), response.data)
84 def test_no_user(self):
85 result = self.app.get('/', follow_redirects=True)
86 self.assertEqual(result.status_code, 500)
87 self.assertIn(str.encode('Server misconfigured'), result.data)
89 def test_user_invalid(self):
90 result = self.app.get('/', environ_base={'USER_ROLES': '<invalid>/'}, follow_redirects=True)
91 self.assertEqual(result.status_code, 403)
92 self.assertIn(str.encode('Access denied'), result.data)
94 def test_basic_env(self):
95 result = self.app.get('/', environ_base={'USER': 'testuser', 'ROLES':''}, follow_redirects=True)
96 testtext= 'id=\"motion-3\">'
97 self.assertIn(str.encode(testtext), result.data)
99 def test_basic_results_data_details_not_given(self):
100 motion='g1.30190402.001'
101 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
102 self.assertEqual(result.status_code, 404)
103 self.assertIn(str.encode('Error, Not found'), result.data)
105 def test_no_proxy(self):
106 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
107 self.assertEqual(result.status_code, 403)
108 self.assertIn(str.encode('Forbidden'), result.data)
110 def test_no_proxy_add(self):
111 result = self.app.post('proxy/add', environ_base={'USER_ROLES': user}, follow_redirects=True)
112 self.assertEqual(result.status_code, 403)
113 self.assertIn(str.encode('Forbidden'), result.data)
115 def test_no_proxy_revoke(self):
116 result = self.app.post('proxy/revoke', environ_base={'USER_ROLES': user}, follow_redirects=True)
117 self.assertEqual(result.status_code, 403)
118 self.assertIn(str.encode('Forbidden'), result.data)
120 def test_no_proxy_revokeAll(self):
121 result = self.app.post('proxy/revokeall', environ_base={'USER_ROLES': user}, follow_redirects=True)
122 self.assertEqual(result.status_code, 403)
123 self.assertIn(str.encode('Forbidden'), result.data)
125 class VoterTests(BasicTest):
130 user='testuser/vote:*'
138 def test_main_page(self):
139 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
140 self.assertEqual(response.status_code, 200)
142 def test_home_data(self):
143 result = self.app.get('/', environ_base={'USER_ROLES': user})
144 self.assertNotIn("<select class=\"float form-control\" name=\"category\">", str(result.data) )
146 def test_vote_yes(self):
147 motion='g1.20200402.004'
148 response = self.createVote(user, motion, 'yes', userid)
149 self.assertEqual(response.status_code, 302)
150 result = self.app.get('/', environ_base={'USER_ROLES': user})
151 resulttext=self.buildResultText('A fourth motion', 1, 0, 0)
152 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
153 testtext= 'class=\"btn btn-success\" name=\"vote\" value="yes" id="vote-yes">Yes</button>'
154 self.assertIn(str.encode(testtext), result.data)
155 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
156 self.assertIn(str.encode(testtext), result.data)
157 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
158 self.assertIn(str.encode(testtext), result.data)
160 def test_vote_no(self):
161 motion='g1.20200402.004'
162 response = self.createVote(user, motion, 'no', userid)
163 self.assertEqual(response.status_code, 302)
164 result = self.app.get('/', environ_base={'USER_ROLES': user})
165 resulttext=self.buildResultText('A fourth motion', 0, 1, 0)
166 self.assertIn(str.encode(resulttext), result.data)
167 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
168 testtext= 'class="btn btn-primary" name="vote\" value=\"yes\" id=\"vote-yes\">Yes</button>'
169 self.assertIn(str.encode(testtext), result.data)
170 testtext= 'class=\"btn btn-success\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
171 self.assertIn(str.encode(testtext), result.data)
172 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
173 self.assertIn(str.encode(testtext), result.data)
175 def test_vote_abstain(self):
176 motion='g1.20200402.004'
177 response = self.createVote(user, motion, 'abstain', userid)
178 self.assertEqual(response.status_code, 302)
179 result = self.app.get('/', environ_base={'USER_ROLES': user})
180 resulttext=self.buildResultText('A fourth motion', 0, 0, 1)
181 self.assertIn(str.encode(resulttext), result.data)
182 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
183 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"yes\" id=\"vote-yes\">Yes</button>'
184 self.assertIn(str.encode(testtext), result.data)
185 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
186 self.assertIn(str.encode(testtext), result.data)
187 testtext= 'class=\"btn btn-success\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
188 self.assertIn(str.encode(testtext), result.data)
190 def test_vote_change(self):
191 motion='g1.20200402.004'
192 response = self.createVote(user, motion, 'yes', userid)
193 self.assertEqual(response.status_code, 302)
194 result = self.app.get('/', environ_base={'USER_ROLES': user})
195 resulttext=self.buildResultText('A fourth motion', 1, 0, 0)
196 self.assertIn(str.encode(resulttext), result.data)
197 response = self.createVote(user, motion, 'no', userid)
198 self.assertEqual(response.status_code, 302)
199 result = self.app.get('/', environ_base={'USER_ROLES': user})
200 resulttext=self.buildResultText('A fourth motion', 0, 1, 0)
201 self.assertIn(str.encode(resulttext), result.data)
202 response = self.createVote(user, motion, 'abstain', userid)
203 self.assertEqual(response.status_code, 302)
204 result = self.app.get('/', environ_base={'USER_ROLES': user})
205 resulttext=self.buildResultText('A fourth motion', 0, 0, 1)
206 self.assertIn(str.encode(resulttext), result.data)
208 def test_vote_group(self):
209 motion='g1.20200402.004'
210 response = self.createVote(user, motion, 'yes', userid)
211 self.assertEqual(response.status_code, 302)
213 motion='g1.20200402.004'
214 user1='testuser/vote:group1'
215 response = self.createVote(user1, motion, 'yes', userid)
216 self.assertEqual(response.status_code, 302)
218 motion='g1.20200402.004'
219 user1='testuser/vote:group1 vote:group2'
220 response = self.createVote(user1, motion, 'yes', userid)
221 self.assertEqual(response.status_code, 302)
223 def test_vote_wrong_group(self):
224 motion='g1.20200402.004'
225 user1='testuser/vote:group2'
226 response = self.createVote(user1, motion, 'yes', userid)
227 self.assertEqual(response.status_code, 403)
228 self.assertIn(str.encode('Forbidden'), response.data)
230 def test_vote_closed(self):
231 motion='g1.20200402.002'
232 response = self.createVote(user, motion, 'abstain', userid)
233 self.assertEqual(response.status_code, 403)
234 self.assertIn(str.encode('Error, out of time'), response.data)
236 def test_vote_canceled(self):
237 motion='g1.20200402.003'
238 response = self.createVote(user, motion, 'abstain', userid)
239 self.assertEqual(response.status_code, 403)
240 self.assertIn(str.encode('Error, motion was canceled'), response.data)
242 def test_vote_not_given(self):
243 motion='g1.30190402.001'
244 response = self.createVote(user, motion, 'abstain', userid)
245 self.assertEqual(response.status_code, 404)
246 self.assertIn(str.encode('Error, Not found'), response.data)
248 def test_cancelMotion(self):
249 motion='g1.20200402.004'
251 response = self.cancelMotion(user, motion, reason)
252 self.assertEqual(response.status_code, 403)
253 self.assertIn(str.encode('Forbidden'), response.data)
255 def test_finishMotion(self):
256 motion='g1.20200402.004'
257 response = self.finishMotion(user, motion)
258 self.assertEqual(response.status_code, 403)
259 self.assertIn(str.encode('Forbidden'), response.data)
261 def test_see_old_vote(self):
262 motion='g1.20200402.002'
263 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
264 testtext= '<div>Proposed: 2020-04-02 21:41:26 (UTC) by User A</div>\n <div>Votes until: 2020-04-04 21:41:26 (UTC)</div>'\
265 + '\n </div>\n </div>\n <div class="card-body">\n <p><p>A second motion</p></p>\n </div>\n</div>'\
266 + '\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
267 self.assertIn(str.encode(testtext), result.data)
269 def test_createMotion(self):
272 response = self.createMotion(user, title, content, '3', 'group1')
273 self.assertEqual(response.status_code, 403)
274 self.assertIn(str.encode('Forbidden'), response.data)
277 class CreateMotionTests(BasicTest):
282 user='testuser/vote:* create:* cancel:* finish:*'
288 def test_main_page(self):
289 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
290 self.assertEqual(response.status_code, 200)
292 def test_home_data(self):
293 result = self.app.get('/', environ_base={'USER_ROLES': user})
295 # assert the response data
296 self.assertIn(b'User: testuser', result.data)
297 self.assertIn("<select class=\"float form-control\" name=\"category\">", str(result.data) )
299 def test_createMotion(self):
302 response = self.createMotion(user, title, content, '3', 'group1')
303 self.assertEqual(response.status_code, 302)
304 result = self.app.get('/', environ_base={'USER_ROLES': user})
305 self.assertIn(str.encode(title), result.data)
306 self.assertIn(str.encode(content), result.data)
307 self.assertIn(str.encode('g1.'+datetime.today().strftime('%Y%m%d')+'.001'), result.data)
308 testtext='<a class=\"btn btn-primary" href=\"/motion/g1.'+datetime.today().strftime('%Y%m%d')+'.001\" role=\"button\">Vote</a>'
309 self.assertIn(str.encode(testtext), result.data)
313 response = self.createMotion(user, title, content, '3', 'group1')
314 self.assertEqual(response.status_code, 302)
315 result = self.app.get('/', environ_base={'USER_ROLES': user})
316 self.assertIn(str.encode(title), result.data)
317 self.assertIn(str.encode(content), result.data)
318 self.assertIn(str.encode('g1.'+datetime.today().strftime('%Y%m%d')+'.002'), result.data)
322 response = self.createMotion(user, title, content, '3', 'group2')
323 self.assertEqual(response.status_code, 302)
324 result = self.app.get('/', environ_base={'USER_ROLES': user})
325 self.assertIn(str.encode(title), result.data)
326 self.assertIn(str.encode(content), result.data)
327 self.assertIn(str.encode('g2.'+datetime.today().strftime('%Y%m%d')+'.001'), result.data)
331 user1='testuser/vote:* create:group1 cancel:*'
332 response = self.createMotion(user1, title, content, '3', 'group1')
333 self.assertEqual(response.status_code, 302)
337 user1='testuser/vote:* create:group1 create:group2 cancel:*'
338 response = self.createMotion(user1, title, content, '3', 'group1')
339 self.assertEqual(response.status_code, 302)
342 def test_createMotionMarkdown(self):
343 title='Markdown Test'
344 content= 'MyMotionBody MD [text](https//domain.tld/link)'
345 response = self.createMotion(user, title, content, '3', 'group1')
346 self.assertEqual(response.status_code, 302)
347 result = self.app.get('/', environ_base={'USER_ROLES': user})
348 self.assertIn(str.encode(title), result.data)
349 self.assertIn(b'MyMotionBody MD <a href=\"https//domain.tld/link\">text</a>', result.data)
351 def test_createMotionMarkdownDirectLink(self):
352 title='Markdown Test Link'
353 content='MyMotionBody MD <a href=\"https//domain.tld/link\">direct</a'
354 response = self.createMotion(user, title, content, '3', 'group1')
355 self.assertEqual(response.status_code, 302)
356 result = self.app.get('/', environ_base={'USER_ROLES': user})
357 self.assertIn(str.encode(title), result.data)
358 self.assertIn(b'MyMotionBody MD <a href="https//domain.tld/link">direct</a', result.data)
360 def test_createMotionMarkdownCombined(self):
361 title='Markdown Test Link'
362 content='Body [combined](https//domain.tld/link) <a href=\"https//domain.tld/link\">combined1</a'
363 response = self.createMotion(user, title, content, '3', 'group1')
364 self.assertEqual(response.status_code, 302)
365 result = self.app.get('/', environ_base={'USER_ROLES': user})
366 self.assertIn(str.encode(title), result.data)
367 self.assertIn(b'Body <a href=\"https//domain.tld/link\">combined</a> <a href="https//domain.tld/link">combined1</a', result.data)
369 def test_createMotionWrongDayLength(self):
372 response = self.createMotion(user, title, content, '21', 'group1')
373 self.assertEqual(response.status_code, 400)
374 self.assertIn(str.encode('Error, invalid length'), response.data)
376 def test_createMotionMissingData(self):
379 response = self.createMotion(user, title, content, '3', 'group1')
380 self.assertEqual(response.status_code, 400)
381 self.assertIn(str.encode('Error, missing title'), response.data)
383 response = self.createMotion(user, title, content, '3', 'group1')
384 self.assertEqual(response.status_code, 400)
385 self.assertIn(str.encode('Error, missing content'), response.data)
387 content='New Content'
388 response = self.createMotion(user, title, content, '3', 'group1')
389 self.assertEqual(response.status_code, 400)
390 self.assertIn(str.encode('Error, missing title'), response.data)
392 def test_createMotionWrongGroup(self):
395 response = self.createMotion(user, title, content, '3', 'test1')
396 self.assertEqual(response.status_code, 403)
397 self.assertIn(str.encode('Forbidden'), response.data)
399 user1='testuser/vote:* create:group1 cancel:*'
400 response = self.createMotion(user1, title, content, '3', 'group2')
401 self.assertEqual(response.status_code, 403)
402 self.assertIn(str.encode('Forbidden'), response.data)
404 def test_SeeCancelMotion(self):
407 motion='g1.20200402.004'
408 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
409 testtext= '<button type="submit" class="btn btn-danger btn-confirm" data-confirm="Do you really want to cancel the motion?" '\
410 + 'data-reply="Cancel,Confirm" name="cancel" value="cancel" id="cancel">Cancel</button>'
411 self.assertIn(str.encode(testtext), result.data)
413 motion='g1.20200402.004'
414 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': 'testuser/vote:*'}, follow_redirects=True)
415 testtext= '<button type="submit" class="btn btn-danger btn-confirm" data-confirm="Do you really want to cancel the motion?" '\
416 + 'data-reply="Cancel,Confirm" name="cancel" value="cancel" id="cancel">Cancel</button>'
417 self.assertNotIn(str.encode(testtext), result.data)
419 def test_cancelMotion(self):
422 motion='g1.20200402.004'
424 response = self.cancelMotion(user, motion, reason)
425 self.assertEqual(response.status_code, 500)
426 self.assertIn(str.encode('Error, form requires reason'), response.data)
429 response = self.cancelMotion(user, motion, reason)
430 self.assertEqual(response.status_code, 302)
431 result = self.app.get('/', environ_base={'USER_ROLES': user})
432 self.assertIn(b'Cancelation reason: ' + str.encode(reason), result.data)
434 motion='g1.20190402.001'
436 response = self.cancelMotion(user, motion, reason)
437 self.assertEqual(response.status_code, 404)
438 self.assertIn(str.encode('Error, Not found'), response.data)
440 motion='g1.30200402.001'
442 response = self.cancelMotion(user, motion, reason)
443 self.assertEqual(response.status_code, 404)
444 self.assertIn(str.encode('Error, Not found'), response.data)
446 motion='g1.20200402.004'
447 response = self.cancelMotion(user, motion, reason)
448 self.assertEqual(response.status_code, 403)
449 self.assertIn(str.encode('Error, motion was canceled'), response.data)
451 def test_SeeFinishMotion(self):
454 motion='g1.20200402.004'
455 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
456 testtext= '<button type="submit" class="btn btn-danger btn-confirm" data-confirm="Do you really want to finish the motion?" '\
457 + 'data-reply="Cancel,Confirm" name="finish" value="finish" id="finish">Finish</button>'
458 self.assertIn(str.encode(testtext), result.data)
460 motion='g1.20200402.004'
461 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': 'testuser/vote:*'}, follow_redirects=True)
462 testtext= '<button type="submit" class="btn btn-danger btn-confirm" data-confirm="Do you really want to finish the motion?" '\
463 + 'data-reply="Cancel,Confirm" name="finish" value="finish" id="finish">Finish</button>'
464 self.assertNotIn(str.encode(testtext), result.data)
466 def test_finishMotion(self):
469 motion='g1.20200402.004'
470 response = self.finishMotion(user, motion)
471 self.assertEqual(response.status_code, 302)
472 result = self.app.get('/', environ_base={'USER_ROLES': user})
473 self.assertIn(b'Motion D</span> (Finished)', result.data)
475 motion='g1.30190402.001'
476 response = self.finishMotion(user, motion)
477 self.assertEqual(response.status_code, 404)
478 self.assertIn(str.encode('Error, Not found'), response.data)
480 motion='g1.20200402.001'
481 response = self.finishMotion(user, motion)
482 self.assertEqual(response.status_code, 403)
483 self.assertIn(str.encode('Error, out of time'), response.data)
485 def test_createMotionWait(self):
486 # test no limit given
490 response = self.createMotion(user, title, content, '3', 'group1')
491 self.assertEqual(response.status_code, 302)
493 # test different host
494 app.config.update(MOTION_WAIT_MINUTES={'127.0.0.1:5001':1})
495 response = self.createMotion(user, title, content, '3', 'group1')
496 self.assertEqual(response.status_code, 302)
499 app.config.update(MOTION_WAIT_MINUTES={'127.0.0.1:5000':3})
500 response = self.createMotion(user, title, content, '3', 'group1')
501 self.assertIn(str.encode('Error, time between last motion to short. The current setting is 3 minute(s).'), response.data)
503 class AuditMotionTests(BasicTest):
508 user='testuser/audit:*'
514 def test_see_old_vote(self):
515 motion='g1.20200402.002'
516 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
517 testtext= '<div class="motion card" id="votes">\n <div class="card-heading text-white bg-info">\n Motion Votes\n </div>'\
518 + '\n <div class="card-body">\n <div>User A: yes</div>\n <div>User B: no</div>'\
519 + '\n <div>User C: no</div>\n </div>\n</div>\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
520 self.assertIn(str.encode(testtext), result.data)
523 if __name__ == "__main__":