1 from datetime import datetime
2 from tests.test_basics import BasicTest
6 # no specific rights required
7 class GeneralTests(BasicTest):
20 def test_main_page(self):
21 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
22 self.assertEqual(response.status_code, 200)
24 def test_basic_results_data(self):
25 result = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
26 testtext= '<div class="motion card" id="motion-3">\n <div class="motion-title card-heading alert-warning">'\
27 + '\n <span class="title-text">Motion C</span> (Canceled)\n <span class="motion-type">group1</span>'\
28 + '\n <div># g1.20200402.003'\
29 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.003" role="button">Result</a>'\
30 + '\n </div>\n <div class="date">'\
31 + '\n <div>Proposed: 2020-04-02 21:47:24 (UTC) by User A</div>'\
32 + '\n <div>Canceled: 2020-04-03 21:48:24 (UTC) by User A</div>\n </div>\n </div>'\
33 + '\n <div class="card-body">\n <p><p>A third motion</p></p>'\
34 + '\n <p>\nYes <span class="badge badge-pill badge-secondary">1</span><br>'\
35 + '\nNo <span class="badge badge-pill badge-secondary">0</span><br>'\
36 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>'\
37 + '\n <p>Cancelation reason: Entered with wrong text</p>\n </div>\n</div>\n'
38 self.assertIn(str.encode(testtext), result.data)
39 testtext= '<div class="motion card" id="motion-2">\n <div class="motion-title card-heading alert-danger">'\
40 + '\n <span class="title-text">Motion B</span> (Finished)\n <span class="motion-type">group1</span>'\
41 + '\n <div># g1.20200402.002'\
42 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.002" role="button">Result</a>'\
43 + '\n </div>\n <div class="date">\n <div>Proposed: 2020-04-02 21:41:26 (UTC) by User A</div>'\
44 + '\n <div>Votes until: 2020-04-04 21:41:26 (UTC)</div>\n </div>\n </div>'\
45 + '\n <div class="card-body">\n <p><p>A second motion</p></p>\n <p>'\
46 + '\nYes <span class="badge badge-pill badge-secondary">1</span><br>'\
47 + '\nNo <span class="badge badge-pill badge-secondary">2</span><br>'\
48 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>\n </div>\n</div>\n'
49 self.assertIn(str.encode(testtext), result.data)
50 testtext= '<div class="motion card" id="motion-1">\n <div class="motion-title card-heading alert-success">'\
51 + '\n <span class="title-text">Motion A</span> (Finished)\n <span class="motion-type">group1</span>'\
52 + '\n <div># g1.20200402.001'\
53 + '\n <a class="btn btn-primary" href="/motion/g1.20200402.001" role="button">Result</a>'\
54 + '\n </div>\n <div class="date">\n <div>Proposed: 2020-04-02 21:40:33 (UTC) by User A</div>'\
55 + '\n <div>Votes until: 2020-04-02 21:40:33 (UTC)</div>\n </div>\n </div>'\
56 + '\n <div class="card-body">\n <p><p>My special motion</p></p>\n <p>'\
57 + '\nYes <span class="badge badge-pill badge-secondary">2</span><br>'\
58 + '\nNo <span class="badge badge-pill badge-secondary">1</span><br>'\
59 + '\nAbstain <span class="badge badge-pill badge-secondary">0</span><br>\n </p>\n </div>\n</div>\n'
60 self.assertIn(str.encode(testtext), result.data)
61 testtext= 'Proxy management'
62 self.assertNotIn(str.encode(testtext), result.data)
64 # start with second motion
65 result = self.app.get('/', environ_base={'USER_ROLES': user}, query_string=dict(start=2))
66 testtext= 'id=\"motion-3\">'
67 self.assertNotIn(str.encode(testtext), result.data)
68 testtext= 'id=\"motion-2">'
69 self.assertIn(str.encode(testtext), result.data)
70 testtext= 'id=\"motion-1\">'
71 self.assertIn(str.encode(testtext), result.data)
73 def test_basic_results_data_details(self):
74 motion='g1.20200402.002'
75 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
76 testtext= '<p>A second motion</p></p>\n </div>\n</div>\n<a href=\"/?start=2#motion-2\" class=\"btn btn-primary\">Back</a>'
77 self.assertIn(str.encode(testtext), result.data)
80 motion='g1.20200402.004'
81 response = self.createVote(user, motion, 'yes', userid)
82 self.assertEqual(response.status_code, 403)
83 self.assertIn(str.encode('Forbidden'), response.data)
85 def test_no_user(self):
86 result = self.app.get('/', follow_redirects=True)
87 self.assertEqual(result.status_code, 500)
88 self.assertIn(str.encode('Server misconfigured'), result.data)
90 def test_user_invalid(self):
91 result = self.app.get('/', environ_base={'USER_ROLES': '<invalid>/'}, follow_redirects=True)
92 self.assertEqual(result.status_code, 403)
93 self.assertIn(str.encode('Access denied'), result.data)
95 def test_basic_env(self):
96 result = self.app.get('/', environ_base={'USER': 'testuser', 'ROLES':''}, follow_redirects=True)
97 testtext= 'id=\"motion-3\">'
98 self.assertIn(str.encode(testtext), result.data)
100 def test_basic_results_data_details_not_given(self):
101 motion='g1.30190402.001'
102 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
103 self.assertEqual(result.status_code, 404)
104 self.assertIn(str.encode('Error, Not found'), result.data)
106 def test_no_proxy(self):
107 result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
108 self.assertEqual(result.status_code, 403)
109 self.assertIn(str.encode('Forbidden'), result.data)
111 def test_no_proxy_add(self):
112 result = self.app.post('proxy/add', environ_base={'USER_ROLES': user}, follow_redirects=True)
113 self.assertEqual(result.status_code, 403)
114 self.assertIn(str.encode('Forbidden'), result.data)
116 def test_no_proxy_revoke(self):
117 result = self.app.post('proxy/revoke', environ_base={'USER_ROLES': user}, follow_redirects=True)
118 self.assertEqual(result.status_code, 403)
119 self.assertIn(str.encode('Forbidden'), result.data)
121 def test_no_proxy_revokeAll(self):
122 result = self.app.post('proxy/revokeall', environ_base={'USER_ROLES': user}, follow_redirects=True)
123 self.assertEqual(result.status_code, 403)
124 self.assertIn(str.encode('Forbidden'), result.data)
126 class VoterTests(BasicTest):
131 user='testuser/vote:*'
139 def test_main_page(self):
140 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
141 self.assertEqual(response.status_code, 200)
143 def test_home_data(self):
144 result = self.app.get('/', environ_base={'USER_ROLES': user})
145 self.assertNotIn("<select class=\"float form-control\" name=\"category\">", str(result.data) )
147 def test_vote_yes(self):
148 motion='g1.20200402.004'
149 response = self.createVote(user, motion, 'yes', userid)
150 self.assertEqual(response.status_code, 302)
151 result = self.app.get('/', environ_base={'USER_ROLES': user})
152 resulttext=self.buildResultText('A fourth motion', 1, 0, 0)
153 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
154 testtext= 'class=\"btn btn-success\" name=\"vote\" value="yes" id="vote-yes">Yes</button>'
155 self.assertIn(str.encode(testtext), result.data)
156 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
157 self.assertIn(str.encode(testtext), result.data)
158 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
159 self.assertIn(str.encode(testtext), result.data)
161 def test_vote_no(self):
162 motion='g1.20200402.004'
163 response = self.createVote(user, motion, 'no', userid)
164 self.assertEqual(response.status_code, 302)
165 result = self.app.get('/', environ_base={'USER_ROLES': user})
166 resulttext=self.buildResultText('A fourth motion', 0, 1, 0)
167 self.assertIn(str.encode(resulttext), result.data)
168 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
169 testtext= 'class="btn btn-primary" name="vote\" value=\"yes\" id=\"vote-yes\">Yes</button>'
170 self.assertIn(str.encode(testtext), result.data)
171 testtext= 'class=\"btn btn-success\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
172 self.assertIn(str.encode(testtext), result.data)
173 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
174 self.assertIn(str.encode(testtext), result.data)
176 def test_vote_abstain(self):
177 motion='g1.20200402.004'
178 response = self.createVote(user, motion, 'abstain', userid)
179 self.assertEqual(response.status_code, 302)
180 result = self.app.get('/', environ_base={'USER_ROLES': user})
181 resulttext=self.buildResultText('A fourth motion', 0, 0, 1)
182 self.assertIn(str.encode(resulttext), result.data)
183 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
184 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"yes\" id=\"vote-yes\">Yes</button>'
185 self.assertIn(str.encode(testtext), result.data)
186 testtext= 'class=\"btn btn-primary\" name=\"vote\" value=\"no\" id=\"vote-no\">No</button>'
187 self.assertIn(str.encode(testtext), result.data)
188 testtext= 'class=\"btn btn-success\" name=\"vote\" value=\"abstain\" id=\"vote-abstain\">Abstain</button>'
189 self.assertIn(str.encode(testtext), result.data)
191 def test_vote_change(self):
192 motion='g1.20200402.004'
193 response = self.createVote(user, motion, 'yes', userid)
194 self.assertEqual(response.status_code, 302)
195 result = self.app.get('/', environ_base={'USER_ROLES': user})
196 resulttext=self.buildResultText('A fourth motion', 1, 0, 0)
197 self.assertIn(str.encode(resulttext), result.data)
198 response = self.createVote(user, motion, 'no', userid)
199 self.assertEqual(response.status_code, 302)
200 result = self.app.get('/', environ_base={'USER_ROLES': user})
201 resulttext=self.buildResultText('A fourth motion', 0, 1, 0)
202 self.assertIn(str.encode(resulttext), result.data)
203 response = self.createVote(user, motion, 'abstain', userid)
204 self.assertEqual(response.status_code, 302)
205 result = self.app.get('/', environ_base={'USER_ROLES': user})
206 resulttext=self.buildResultText('A fourth motion', 0, 0, 1)
207 self.assertIn(str.encode(resulttext), result.data)
209 def test_vote_group(self):
210 motion='g1.20200402.004'
211 response = self.createVote(user, motion, 'yes', userid)
212 self.assertEqual(response.status_code, 302)
214 motion='g1.20200402.004'
215 user1='testuser/vote:group1'
216 response = self.createVote(user1, motion, 'yes', userid)
217 self.assertEqual(response.status_code, 302)
219 motion='g1.20200402.004'
220 user1='testuser/vote:group1 vote:group2'
221 response = self.createVote(user1, motion, 'yes', userid)
222 self.assertEqual(response.status_code, 302)
224 def test_vote_wrong_group(self):
225 motion='g1.20200402.004'
226 user1='testuser/vote:group2'
227 response = self.createVote(user1, motion, 'yes', userid)
228 self.assertEqual(response.status_code, 403)
229 self.assertIn(str.encode('Forbidden'), response.data)
231 def test_vote_closed(self):
232 motion='g1.20200402.002'
233 response = self.createVote(user, motion, 'abstain', userid)
234 self.assertEqual(response.status_code, 403)
235 self.assertIn(str.encode('Error, out of time'), response.data)
237 def test_vote_canceled(self):
238 motion='g1.20200402.003'
239 response = self.createVote(user, motion, 'abstain', userid)
240 self.assertEqual(response.status_code, 403)
241 self.assertIn(str.encode('Error, motion was canceled'), response.data)
243 def test_vote_not_given(self):
244 motion='g1.30190402.001'
245 response = self.createVote(user, motion, 'abstain', userid)
246 self.assertEqual(response.status_code, 404)
247 self.assertIn(str.encode('Error, Not found'), response.data)
249 def test_cancelMotion(self):
250 motion='g1.20200402.004'
252 response = self.cancelMotion(user, motion, reason)
253 self.assertEqual(response.status_code, 403)
254 self.assertIn(str.encode('Forbidden'), response.data)
256 def test_finishMotion(self):
257 motion='g1.20200402.004'
258 response = self.finishMotion(user, motion)
259 self.assertEqual(response.status_code, 403)
260 self.assertIn(str.encode('Forbidden'), response.data)
262 def test_see_old_vote(self):
263 motion='g1.20200402.002'
264 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
265 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>'\
266 + '\n </div>\n </div>\n <div class="card-body">\n <p><p>A second motion</p></p>\n </div>\n</div>'\
267 + '\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
268 self.assertIn(str.encode(testtext), result.data)
270 def test_createMotion(self):
273 response = self.createMotion(user, title, content, '3', 'group1')
274 self.assertEqual(response.status_code, 403)
275 self.assertIn(str.encode('Forbidden'), response.data)
278 class CreateMotionTests(BasicTest):
283 user='testuser/vote:* create:* cancel:* finish:*'
289 def test_main_page(self):
290 response = self.app.get('/', environ_base={'USER_ROLES': user}, follow_redirects=True)
291 self.assertEqual(response.status_code, 200)
293 def test_home_data(self):
294 result = self.app.get('/', environ_base={'USER_ROLES': user})
296 # assert the response data
297 self.assertIn(b'User: testuser', result.data)
298 self.assertIn("<select class=\"float form-control\" name=\"category\">", str(result.data) )
300 def test_createMotion(self):
303 response = self.createMotion(user, title, content, '3', 'group1')
304 self.assertEqual(response.status_code, 302)
305 result = self.app.get('/', environ_base={'USER_ROLES': user})
306 self.assertIn(str.encode(title), result.data)
307 self.assertIn(str.encode(content), result.data)
308 self.assertIn(str.encode('g1.'+datetime.today().strftime('%Y%m%d')+'.001'), result.data)
309 testtext='<a class=\"btn btn-primary" href=\"/motion/g1.'+datetime.today().strftime('%Y%m%d')+'.001\" role=\"button\">Vote</a>'
310 self.assertIn(str.encode(testtext), result.data)
314 response = self.createMotion(user, title, content, '3', 'group1')
315 self.assertEqual(response.status_code, 302)
316 result = self.app.get('/', environ_base={'USER_ROLES': user})
317 self.assertIn(str.encode(title), result.data)
318 self.assertIn(str.encode(content), result.data)
319 self.assertIn(str.encode('g1.'+datetime.today().strftime('%Y%m%d')+'.002'), result.data)
323 response = self.createMotion(user, title, content, '3', 'group2')
324 self.assertEqual(response.status_code, 302)
325 result = self.app.get('/', environ_base={'USER_ROLES': user})
326 self.assertIn(str.encode(title), result.data)
327 self.assertIn(str.encode(content), result.data)
328 self.assertIn(str.encode('g2.'+datetime.today().strftime('%Y%m%d')+'.001'), result.data)
332 user1='testuser/vote:* create:group1 cancel:*'
333 response = self.createMotion(user1, title, content, '3', 'group1')
334 self.assertEqual(response.status_code, 302)
338 user1='testuser/vote:* create:group1 create:group2 cancel:*'
339 response = self.createMotion(user1, title, content, '3', 'group1')
340 self.assertEqual(response.status_code, 302)
343 def test_createMotionMarkdown(self):
344 title='Markdown Test'
345 content= 'MyMotionBody MD [text](https//domain.tld/link)'
346 response = self.createMotion(user, title, content, '3', 'group1')
347 self.assertEqual(response.status_code, 302)
348 result = self.app.get('/', environ_base={'USER_ROLES': user})
349 self.assertIn(str.encode(title), result.data)
350 self.assertIn(b'MyMotionBody MD <a href=\"https//domain.tld/link\">text</a>', result.data)
352 def test_createMotionMarkdownDirectLink(self):
353 title='Markdown Test Link'
354 content='MyMotionBody MD <a href=\"https//domain.tld/link\">direct</a'
355 response = self.createMotion(user, title, content, '3', 'group1')
356 self.assertEqual(response.status_code, 302)
357 result = self.app.get('/', environ_base={'USER_ROLES': user})
358 self.assertIn(str.encode(title), result.data)
359 self.assertIn(b'MyMotionBody MD <a href="https//domain.tld/link">direct</a', result.data)
361 def test_createMotionMarkdownCombined(self):
362 title='Markdown Test Link'
363 content='Body [combined](https//domain.tld/link) <a href=\"https//domain.tld/link\">combined1</a'
364 response = self.createMotion(user, title, content, '3', 'group1')
365 self.assertEqual(response.status_code, 302)
366 result = self.app.get('/', environ_base={'USER_ROLES': user})
367 self.assertIn(str.encode(title), result.data)
368 self.assertIn(b'Body <a href=\"https//domain.tld/link\">combined</a> <a href="https//domain.tld/link">combined1</a', result.data)
370 def test_createMotionWrongDayLength(self):
373 response = self.createMotion(user, title, content, '21', 'group1')
374 self.assertEqual(response.status_code, 400)
375 self.assertIn(str.encode('Error, invalid length'), response.data)
377 def test_createMotionMissingData(self):
380 response = self.createMotion(user, title, content, '3', 'group1')
381 self.assertEqual(response.status_code, 400)
382 self.assertIn(str.encode('Error, missing title'), response.data)
384 response = self.createMotion(user, title, content, '3', 'group1')
385 self.assertEqual(response.status_code, 400)
386 self.assertIn(str.encode('Error, missing content'), response.data)
388 content='New Content'
389 response = self.createMotion(user, title, content, '3', 'group1')
390 self.assertEqual(response.status_code, 400)
391 self.assertIn(str.encode('Error, missing title'), response.data)
393 def test_createMotionWrongGroup(self):
396 response = self.createMotion(user, title, content, '3', 'test1')
397 self.assertEqual(response.status_code, 403)
398 self.assertIn(str.encode('Forbidden'), response.data)
400 user1='testuser/vote:* create:group1 cancel:*'
401 response = self.createMotion(user1, title, content, '3', 'group2')
402 self.assertEqual(response.status_code, 403)
403 self.assertIn(str.encode('Forbidden'), response.data)
405 def test_SeeCancelMotion(self):
408 motion='g1.20200402.004'
409 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
410 testtext= '<button type="submit" class="btn btn-danger" 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" name="cancel" value="cancel" id="cancel">Cancel</button>'
416 self.assertNotIn(str.encode(testtext), result.data)
418 def test_cancelMotion(self):
421 motion='g1.20200402.004'
423 response = self.cancelMotion(user, motion, reason)
424 self.assertEqual(response.status_code, 500)
425 self.assertIn(str.encode('Error, form requires reason'), response.data)
428 response = self.cancelMotion(user, motion, reason)
429 self.assertEqual(response.status_code, 302)
430 result = self.app.get('/', environ_base={'USER_ROLES': user})
431 self.assertIn(b'Cancelation reason: ' + str.encode(reason), result.data)
433 motion='g1.20190402.001'
435 response = self.cancelMotion(user, motion, reason)
436 self.assertEqual(response.status_code, 404)
437 self.assertIn(str.encode('Error, Not found'), response.data)
439 motion='g1.30200402.001'
441 response = self.cancelMotion(user, motion, reason)
442 self.assertEqual(response.status_code, 404)
443 self.assertIn(str.encode('Error, Not found'), response.data)
445 motion='g1.20200402.004'
446 response = self.cancelMotion(user, motion, reason)
447 self.assertEqual(response.status_code, 403)
448 self.assertIn(str.encode('Error, motion was canceled'), response.data)
450 def test_SeeFinishMotion(self):
453 motion='g1.20200402.004'
454 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
455 testtext= '<button type="submit" class="btn btn-danger" name="finish" value="finish" id="finish">Finish</button>'
456 self.assertIn(str.encode(testtext), result.data)
458 motion='g1.20200402.004'
459 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': 'testuser/vote:*'}, follow_redirects=True)
460 testtext= '<button type="submit" class="btn btn-danger" name="finish" value="finish" id="finish">Finish</button>'
461 self.assertNotIn(str.encode(testtext), result.data)
463 def test_finishMotion(self):
466 motion='g1.20200402.004'
467 response = self.finishMotion(user, motion)
468 self.assertEqual(response.status_code, 302)
469 result = self.app.get('/', environ_base={'USER_ROLES': user})
470 self.assertIn(b'Motion D</span> (Finished)', result.data)
472 motion='g1.30190402.001'
473 response = self.finishMotion(user, motion)
474 self.assertEqual(response.status_code, 404)
475 self.assertIn(str.encode('Error, Not found'), response.data)
477 motion='g1.20200402.001'
478 response = self.finishMotion(user, motion)
479 self.assertEqual(response.status_code, 403)
480 self.assertIn(str.encode('Error, out of time'), response.data)
482 class AuditMotionTests(BasicTest):
487 user='testuser/audit:*'
493 def test_see_old_vote(self):
494 motion='g1.20200402.002'
495 result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
496 testtext= '<div class="motion card" id="votes">\n <div class="card-heading text-white bg-info">\n Motion Votes\n </div>'\
497 + '\n <div class="card-body">\n <div>User A: yes</div>\n <div>User B: no</div>'\
498 + '\n <div>User C: no</div>\n </div>\n</div>\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
499 self.assertIn(str.encode(testtext), result.data)
502 if __name__ == "__main__":