test_forumthreads_view.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. from django.contrib.auth import get_user_model
  2. from django.core.urlresolvers import reverse
  3. from django.utils.translation import ugettext as _
  4. from misago.acl import add_acl
  5. from misago.acl.testutils import override_acl
  6. from misago.forums.models import Forum
  7. from misago.users.testutils import AuthenticatedUserTestCase
  8. from misago.threads import testutils
  9. from misago.threads.models import Thread, Label
  10. from misago.threads.moderation import ModerationError
  11. from misago.threads.views.generic.forum import (ForumActions, ForumFiltering,
  12. ForumThreads)
  13. class ForumViewHelperTestCase(AuthenticatedUserTestCase):
  14. def setUp(self):
  15. super(ForumViewHelperTestCase, self).setUp()
  16. self.forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
  17. self.forum.labels = []
  18. def override_acl(self, new_acl):
  19. new_acl.update({'can_browse': True})
  20. forums_acl = self.user.acl
  21. forums_acl['visible_forums'].append(self.forum.pk)
  22. forums_acl['forums'][self.forum.pk] = new_acl
  23. override_acl(self.user, forums_acl)
  24. self.forum.acl = {}
  25. add_acl(self.user, self.forum)
  26. class MockRequest(object):
  27. def __init__(self, user, method='GET', POST=None):
  28. self.POST = POST or {}
  29. self.user = user
  30. self.session = {}
  31. self.path = '/forum/fake-forum-1/'
  32. class ActionsTests(ForumViewHelperTestCase):
  33. def setUp(self):
  34. super(ActionsTests, self).setUp()
  35. self.user._misago_real_ip = '127.0.0.1'
  36. def test_weight_actions(self):
  37. """ForumActions initializes valid list of available weights"""
  38. self.override_acl({
  39. 'can_change_threads_weight': 0,
  40. })
  41. actions = ForumActions(user=self.user, forum=self.forum)
  42. self.assertEqual(actions.available_actions, [])
  43. self.override_acl({
  44. 'can_change_threads_weight': 1,
  45. })
  46. actions = ForumActions(user=self.user, forum=self.forum)
  47. self.assertEqual(actions.available_actions, [
  48. {
  49. 'action': 'pin',
  50. 'icon': 'bookmark',
  51. 'name': _("Change to pinned")
  52. },
  53. {
  54. 'action': 'reset',
  55. 'icon': 'circle',
  56. 'name': _("Reset weight")
  57. },
  58. ])
  59. self.override_acl({
  60. 'can_change_threads_weight': 2,
  61. })
  62. actions = ForumActions(user=self.user, forum=self.forum)
  63. self.assertEqual(actions.available_actions, [
  64. {
  65. 'action': 'announce',
  66. 'icon': 'star',
  67. 'name': _("Change to announcements")
  68. },
  69. {
  70. 'action': 'pin',
  71. 'icon': 'bookmark',
  72. 'name': _("Change to pinned")
  73. },
  74. {
  75. 'action': 'reset',
  76. 'icon': 'circle',
  77. 'name': _("Reset weight")
  78. },
  79. ])
  80. class ForumFilteringTests(ForumViewHelperTestCase):
  81. def test_get_available_filters(self):
  82. """get_available_filters returns filters varying on forum acl"""
  83. default_acl = {
  84. 'can_see_all_threads': False,
  85. 'can_see_reports': False,
  86. 'can_review_moderated_content': False,
  87. }
  88. cases = (
  89. ('can_see_all_threads', 'my-threads'),
  90. ('can_see_reports', 'reported'),
  91. ('can_review_moderated_content', 'moderated-threads'),
  92. )
  93. for permission, filter_type in cases:
  94. self.override_acl(default_acl)
  95. filtering = ForumFiltering(self.forum, 'misago:forum', {
  96. 'forum_id': self.forum.id,
  97. 'forum_slug': self.forum.slug,
  98. })
  99. available_filters = filtering.get_available_filters()
  100. available_filters = [f['type'] for f in available_filters]
  101. self.assertNotIn(filter_type, available_filters)
  102. acl = default_acl.copy()
  103. acl[permission] = True
  104. self.override_acl(acl)
  105. filtering = ForumFiltering(self.forum, 'misago:forum', {
  106. 'forum_id': self.forum.id,
  107. 'forum_slug': self.forum.slug,
  108. })
  109. available_filters = filtering.get_available_filters()
  110. available_filters = [f['type'] for f in available_filters]
  111. self.assertIn(filter_type, available_filters)
  112. self.forum.labels = [
  113. Label(name='Label A', slug='label-a'),
  114. Label(name='Label B', slug='label-b'),
  115. Label(name='Label C', slug='label-c'),
  116. Label(name='Label D', slug='label-d'),
  117. ]
  118. self.override_acl(default_acl)
  119. ForumFiltering(self.forum, 'misago:forum', {
  120. 'forum_id': self.forum.id,
  121. 'forum_slug': self.forum.slug,
  122. })
  123. available_filters = filtering.get_available_filters()
  124. available_filters = [f['type'] for f in available_filters]
  125. self.assertEqual(len(available_filters), len(self.forum.labels))
  126. for label in self.forum.labels:
  127. self.assertIn(label.slug, available_filters)
  128. def test_clean_kwargs(self):
  129. """clean_kwargs cleans kwargs"""
  130. self.override_acl({
  131. 'can_see_all_threads': True,
  132. 'can_see_reports': True,
  133. 'can_review_moderated_content': True,
  134. })
  135. filtering = ForumFiltering(self.forum, 'misago:forum', {
  136. 'forum_id': self.forum.id,
  137. 'forum_slug': self.forum.slug,
  138. })
  139. available_filters = filtering.get_available_filters()
  140. available_filters = [f['type'] for f in available_filters]
  141. clean_kwargs = filtering.clean_kwargs({'test': 'kwarg'})
  142. self.assertEqual(clean_kwargs, {'test': 'kwarg'})
  143. clean_kwargs = filtering.clean_kwargs({
  144. 'test': 'kwarg',
  145. 'show': 'everything-hue-hue',
  146. })
  147. self.assertEqual(clean_kwargs, {'test': 'kwarg'})
  148. self.assertFalse(filtering.is_active)
  149. self.assertIsNone(filtering.show)
  150. for filter_type in available_filters:
  151. clean_kwargs = filtering.clean_kwargs({
  152. 'test': 'kwarg',
  153. 'show': filter_type,
  154. })
  155. self.assertEqual(clean_kwargs, {
  156. 'test': 'kwarg',
  157. 'show': filter_type,
  158. })
  159. self.assertTrue(filtering.is_active)
  160. self.assertEqual(filtering.show, filter_type)
  161. def test_current(self):
  162. """current returns dict with current filter"""
  163. self.override_acl({
  164. 'can_see_all_threads': True,
  165. 'can_see_reports': True,
  166. 'can_review_moderated_content': True,
  167. })
  168. test_cases = (
  169. ('my-threads', _("My threads")),
  170. ('reported', _("With reported posts")),
  171. ('moderated-threads', _("Moderated threads")),
  172. ('moderated-posts', _("With moderated posts")),
  173. )
  174. for filter_type, name in test_cases:
  175. filtering = ForumFiltering(self.forum, 'misago:forum', {
  176. 'forum_id': self.forum.id,
  177. 'forum_slug': self.forum.slug,
  178. })
  179. filtering.clean_kwargs({'show': filter_type})
  180. self.assertEqual(filtering.current['name'], name)
  181. def test_choices(self):
  182. """choices returns list of dicts with available filters"""
  183. self.override_acl({
  184. 'can_see_all_threads': True,
  185. 'can_see_reports': True,
  186. 'can_review_moderated_content': True,
  187. })
  188. test_cases = (
  189. 'my-threads',
  190. 'reported',
  191. 'moderated-threads',
  192. 'moderated-posts',
  193. )
  194. for filter_type in test_cases:
  195. filtering = ForumFiltering(self.forum, 'misago:forum', {
  196. 'forum_id': self.forum.id,
  197. 'forum_slug': self.forum.slug,
  198. })
  199. filtering.clean_kwargs({'show': filter_type})
  200. choices = [choice['type'] for choice in filtering.choices()]
  201. self.assertNotIn(filter_type, choices)
  202. class ForumThreadsTests(ForumViewHelperTestCase):
  203. def test_empty_list(self):
  204. """list returns empty list of items"""
  205. self.override_acl({
  206. 'can_see_all_threads': True,
  207. 'can_review_moderated_content': False
  208. })
  209. threads = ForumThreads(self.user, self.forum)
  210. threads_list = threads.list()
  211. self.assertEqual(threads_list, [])
  212. def test_list_exception(self):
  213. """
  214. uninitialized list raises exceptions when
  215. page and paginator attributes are accessed
  216. """
  217. self.override_acl({
  218. 'can_see_all_threads': False,
  219. 'can_review_moderated_content': False
  220. })
  221. threads = ForumThreads(self.user, self.forum)
  222. with self.assertRaises(AttributeError):
  223. threads.page
  224. with self.assertRaises(AttributeError):
  225. threads.paginator
  226. def test_list_with_threads(self):
  227. """list returns list of visible threads"""
  228. test_threads = [
  229. testutils.post_thread(
  230. forum=self.forum,
  231. title="Hello, I am thread",
  232. is_moderated=False,
  233. poster=self.user),
  234. testutils.post_thread(
  235. forum=self.forum,
  236. title="Hello, I am moderated thread",
  237. is_moderated=True,
  238. poster=self.user),
  239. testutils.post_thread(
  240. forum=self.forum,
  241. title="Hello, I am other user thread",
  242. is_moderated=False,
  243. poster="Bob"),
  244. testutils.post_thread(
  245. forum=self.forum,
  246. title="Hello, I am other user moderated thread",
  247. is_moderated=True,
  248. poster="Bob"),
  249. ]
  250. self.override_acl({
  251. 'can_see_all_threads': False,
  252. 'can_review_moderated_content': False
  253. })
  254. threads = ForumThreads(self.user, self.forum)
  255. self.assertEqual(threads.list(), [test_threads[1], test_threads[0]])
  256. self.override_acl({
  257. 'can_see_all_threads': True,
  258. 'can_review_moderated_content': False
  259. })
  260. threads = ForumThreads(self.user, self.forum)
  261. self.assertEqual(threads.list(),
  262. [test_threads[2], test_threads[1], test_threads[0]])
  263. self.override_acl({
  264. 'can_see_all_threads': True,
  265. 'can_review_moderated_content': True
  266. })
  267. threads = ForumThreads(self.user, self.forum)
  268. test_threads.reverse()
  269. self.assertEqual(threads.list(), test_threads)
  270. self.assertTrue(threads.page)
  271. self.assertTrue(threads.paginator)
  272. class ForumThreadsViewTests(AuthenticatedUserTestCase):
  273. def setUp(self):
  274. super(ForumThreadsViewTests, self).setUp()
  275. self.forum = Forum.objects.all_forums().filter(role="forum")[:1][0]
  276. self.link = self.forum.get_absolute_url()
  277. self.forum.delete_content()
  278. def override_acl(self, new_acl):
  279. forums_acl = self.user.acl
  280. if new_acl['can_see']:
  281. forums_acl['visible_forums'].append(self.forum.pk)
  282. else:
  283. forums_acl['visible_forums'].remove(self.forum.pk)
  284. forums_acl['forums'][self.forum.pk] = new_acl
  285. override_acl(self.user, forums_acl)
  286. def test_cant_see(self):
  287. """has no permission to see forum"""
  288. self.override_acl({
  289. 'can_see': 0,
  290. 'can_browse': 0,
  291. })
  292. response = self.client.get(self.link)
  293. self.assertEqual(response.status_code, 404)
  294. def test_cant_browse(self):
  295. """has no permission to browse forum"""
  296. self.override_acl({
  297. 'can_see': 1,
  298. 'can_browse': 0,
  299. })
  300. response = self.client.get(self.link)
  301. self.assertEqual(response.status_code, 403)
  302. def test_can_browse_empty(self):
  303. """has permission to browse forum, sees empty list"""
  304. self.override_acl({
  305. 'can_see': 1,
  306. 'can_browse': 1,
  307. })
  308. response = self.client.get(self.link)
  309. self.assertEqual(response.status_code, 200)
  310. self.assertIn("No threads", response.content)
  311. def test_owned_threads_visibility(self):
  312. """
  313. can_see_all_threads=0 displays only owned threads to authenticated user
  314. """
  315. test_acl = {
  316. 'can_see': 1,
  317. 'can_browse': 1,
  318. 'can_see_all_threads': 0,
  319. 'can_review_moderated_content': 0,
  320. }
  321. other_moderated_title = "Test other user moderated thread"
  322. testutils.post_thread(
  323. forum=self.forum, title=other_moderated_title, is_moderated=True)
  324. other_title = "Test other user thread"
  325. testutils.post_thread(forum=self.forum, title=other_title)
  326. owned_title = "Test authenticated user thread"
  327. testutils.post_thread(
  328. forum=self.forum,
  329. title=owned_title,
  330. poster=self.user)
  331. owned_moderated_title = "Test authenticated user moderated thread"
  332. testutils.post_thread(
  333. forum=self.forum,
  334. title=owned_moderated_title,
  335. poster=self.user,
  336. is_moderated=True)
  337. self.override_acl(test_acl)
  338. response = self.client.get(self.link)
  339. self.assertEqual(response.status_code, 200)
  340. self.assertNotIn(other_title, response.content)
  341. self.assertNotIn(other_moderated_title, response.content)
  342. self.assertIn(owned_title, response.content)
  343. self.assertIn(owned_moderated_title, response.content)
  344. self.assertNotIn('show-my-threads', response.content)
  345. def test_moderated_threads_visibility(self):
  346. """moderated threads are not rendered to non-moderator, except owned"""
  347. test_acl = {
  348. 'can_see': 1,
  349. 'can_browse': 1,
  350. 'can_see_all_threads': 1,
  351. 'can_review_moderated_content': 0,
  352. }
  353. test_title = "Test moderated thread"
  354. thread = testutils.post_thread(
  355. forum=self.forum, title=test_title, is_moderated=True)
  356. self.override_acl(test_acl)
  357. response = self.client.get(self.link)
  358. self.assertEqual(response.status_code, 200)
  359. self.assertNotIn(test_title, response.content)
  360. test_title = "Test owned moderated thread"
  361. thread = testutils.post_thread(
  362. forum=self.forum,
  363. title=test_title,
  364. is_moderated=True,
  365. poster=self.user)
  366. self.override_acl(test_acl)
  367. response = self.client.get(self.link)
  368. self.assertEqual(response.status_code, 200)
  369. self.assertIn(test_title, response.content)
  370. def test_owned_threads_filter(self):
  371. """owned threads filter is available to authenticated user"""
  372. test_acl = {
  373. 'can_see': 1,
  374. 'can_browse': 1,
  375. 'can_see_all_threads': 1,
  376. 'can_review_moderated_content': 0,
  377. }
  378. other_moderated_title = "Test other user moderated thread"
  379. testutils.post_thread(
  380. forum=self.forum, title=other_moderated_title, is_moderated=True)
  381. other_title = "Test other user thread"
  382. testutils.post_thread(forum=self.forum, title=other_title)
  383. owned_title = "Test authenticated user thread"
  384. testutils.post_thread(
  385. forum=self.forum,
  386. title=owned_title,
  387. poster=self.user)
  388. owned_moderated_title = "Test authenticated user moderated thread"
  389. testutils.post_thread(
  390. forum=self.forum,
  391. title=owned_moderated_title,
  392. poster=self.user,
  393. is_moderated=True)
  394. self.override_acl(test_acl)
  395. response = self.client.get(self.link)
  396. self.assertEqual(response.status_code, 200)
  397. self.assertIn(other_title, response.content)
  398. self.assertNotIn(other_moderated_title, response.content)
  399. self.assertIn(owned_title, response.content)
  400. self.assertIn(owned_moderated_title, response.content)
  401. self.assertIn('show-my-threads', response.content)
  402. self.override_acl(test_acl)
  403. response = self.client.get(reverse('misago:forum', kwargs={
  404. 'forum_id': self.forum.id,
  405. 'forum_slug': self.forum.slug,
  406. 'show': 'my-threads',
  407. }))
  408. self.assertEqual(response.status_code, 200)
  409. self.assertNotIn(other_title, response.content)
  410. self.assertNotIn(other_moderated_title, response.content)
  411. self.assertIn(owned_title, response.content)
  412. self.assertIn(owned_moderated_title, response.content)
  413. def test_moderated_threads_filter(self):
  414. """moderated threads filter is available to moderator"""
  415. test_acl = {
  416. 'can_see': 1,
  417. 'can_browse': 1,
  418. 'can_see_all_threads': 1,
  419. 'can_review_moderated_content': 0,
  420. }
  421. not_moderated_title = "Not moderated thread"
  422. testutils.post_thread(forum=self.forum, title=not_moderated_title)
  423. hidden_title = "Test moderated thread"
  424. testutils.post_thread(
  425. forum=self.forum, title=hidden_title, is_moderated=True)
  426. visible_title = "Test owned moderated thread"
  427. testutils.post_thread(
  428. forum=self.forum,
  429. title=visible_title,
  430. is_moderated=True,
  431. poster=self.user)
  432. self.override_acl(test_acl)
  433. response = self.client.get(self.link)
  434. self.assertEqual(response.status_code, 200)
  435. self.assertIn(not_moderated_title, response.content)
  436. self.assertNotIn(hidden_title, response.content)
  437. self.assertIn(visible_title, response.content)
  438. self.assertNotIn('show-moderated-threads', response.content)
  439. self.assertNotIn('show-moderated-posts', response.content)
  440. self.override_acl(test_acl)
  441. response = self.client.get(reverse('misago:forum', kwargs={
  442. 'forum_id': self.forum.id,
  443. 'forum_slug': self.forum.slug,
  444. 'show': 'moderated-threads',
  445. }))
  446. self.assertEqual(response.status_code, 302)
  447. self.override_acl(test_acl)
  448. response = self.client.get(reverse('misago:forum', kwargs={
  449. 'forum_id': self.forum.id,
  450. 'forum_slug': self.forum.slug,
  451. 'show': 'moderated-posts',
  452. }))
  453. self.assertEqual(response.status_code, 302)
  454. test_acl = {
  455. 'can_see': 1,
  456. 'can_browse': 1,
  457. 'can_see_all_threads': 1,
  458. 'can_review_moderated_content': 1,
  459. }
  460. self.override_acl(test_acl)
  461. response = self.client.get(self.link)
  462. self.assertEqual(response.status_code, 200)
  463. self.assertIn(not_moderated_title, response.content)
  464. self.assertIn(hidden_title, response.content)
  465. self.assertIn(visible_title, response.content)
  466. self.assertIn('show-moderated-threads', response.content)
  467. self.assertIn('show-moderated-posts', response.content)
  468. self.override_acl(test_acl)
  469. response = self.client.get(reverse('misago:forum', kwargs={
  470. 'forum_id': self.forum.id,
  471. 'forum_slug': self.forum.slug,
  472. 'show': 'moderated-threads',
  473. }))
  474. self.assertEqual(response.status_code, 200)
  475. self.assertNotIn(not_moderated_title, response.content)
  476. self.assertIn(hidden_title, response.content)
  477. self.assertIn(visible_title, response.content)
  478. self.assertIn('show-moderated-threads', response.content)
  479. self.assertIn('show-moderated-posts', response.content)
  480. def test_anonymous_request(self):
  481. """view renders to anonymous users"""
  482. anon_title = "Hello Anon!"
  483. testutils.post_thread(forum=self.forum, title=anon_title)
  484. response = self.client.get(self.link)
  485. self.assertEqual(response.status_code, 200)
  486. self.assertIn(anon_title, response.content)
  487. def test_moderate_threads_weight(self):
  488. """moderation allows for changing threads weight"""
  489. test_acl = {
  490. 'can_see': 1,
  491. 'can_browse': 1,
  492. 'can_see_all_threads': 1,
  493. 'can_change_threads_weight': 2
  494. }
  495. self.override_acl(test_acl)
  496. response = self.client.get(self.link)
  497. self.assertEqual(response.status_code, 200)
  498. self.assertIn("Change to announcements", response.content)
  499. announcement = testutils.post_thread(self.forum, weight=2)
  500. pinned = testutils.post_thread(self.forum, weight=1)
  501. thread = testutils.post_thread(self.forum, weight=0)
  502. # annouce nothing
  503. self.override_acl(test_acl)
  504. response = self.client.post(self.link, data={'action': 'announce'})
  505. self.assertEqual(response.status_code, 200)
  506. self.assertIn("You have to select at least one thread.",
  507. response.content)
  508. # make announcement announcement
  509. self.override_acl(test_acl)
  510. response = self.client.post(self.link, data={
  511. 'action': 'announce', 'thread': [announcement.pk]
  512. })
  513. self.assertEqual(response.status_code, 302)
  514. self.override_acl(test_acl)
  515. response = self.client.get(self.link)
  516. self.assertEqual(response.status_code, 200)
  517. self.assertIn("No threads were changed to announcements.",
  518. response.content)
  519. # make non-announcements announcements
  520. self.override_acl(test_acl)
  521. response = self.client.post(self.link, data={
  522. 'action': 'announce', 'thread': [pinned.pk, thread.pk]
  523. })
  524. self.assertEqual(response.status_code, 302)
  525. self.override_acl(test_acl)
  526. response = self.client.get(self.link)
  527. self.assertEqual(response.status_code, 200)
  528. self.assertIn("2 threads were changed to announcements.",
  529. response.content)
  530. pinned = Thread.objects.get(pk=pinned.pk)
  531. thread = Thread.objects.get(pk=thread.pk)
  532. self.assertEqual(pinned.weight, 2)
  533. self.assertEqual(thread.weight, 2)
  534. # make threads pinned
  535. self.override_acl(test_acl)
  536. response = self.client.post(self.link, data={
  537. 'action': 'pin', 'thread': [pinned.pk, thread.pk]
  538. })
  539. self.assertEqual(response.status_code, 302)
  540. self.override_acl(test_acl)
  541. response = self.client.get(self.link)
  542. self.assertEqual(response.status_code, 200)
  543. self.assertIn("2 threads were pinned.", response.content)
  544. announcement = Thread.objects.get(pk=announcement.pk)
  545. pinned = Thread.objects.get(pk=pinned.pk)
  546. thread = Thread.objects.get(pk=thread.pk)
  547. self.assertEqual(announcement.weight, 2)
  548. self.assertEqual(pinned.weight, 1)
  549. self.assertEqual(thread.weight, 1)
  550. # reset threads pinned
  551. self.override_acl(test_acl)
  552. response = self.client.post(self.link, data={
  553. 'action': 'reset', 'thread': [thread.pk]
  554. })
  555. self.assertEqual(response.status_code, 302)
  556. self.override_acl(test_acl)
  557. response = self.client.get(self.link)
  558. self.assertEqual(response.status_code, 200)
  559. self.assertIn("1 thread weight was reset.", response.content)
  560. announcement = Thread.objects.get(pk=announcement.pk)
  561. pinned = Thread.objects.get(pk=pinned.pk)
  562. thread = Thread.objects.get(pk=thread.pk)
  563. self.assertEqual(announcement.weight, 2)
  564. self.assertEqual(pinned.weight, 1)
  565. self.assertEqual(thread.weight, 0)