tests_models.py 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2013 The Distro Tracker Developers
  3. # See the COPYRIGHT file at the top-level directory of this distribution and
  4. # at http://deb.li/DTAuthors
  5. #
  6. # This file is part of Distro Tracker. It is subject to the license terms
  7. # in the LICENSE file found in the top-level directory of this
  8. # distribution and at http://deb.li/DTLicense. No part of Distro Tracker,
  9. # including this file, may be copied, modified, propagated, or distributed
  10. # except according to the terms contained in the LICENSE file.
  11. """
  12. Tests for the Distro Tracker core module's models.
  13. """
  14. from __future__ import unicode_literals
  15. from distro_tracker.test import TestCase
  16. from django.test.utils import override_settings
  17. from django.core.files.base import ContentFile
  18. from django.core.exceptions import ValidationError, ObjectDoesNotExist
  19. from django.core.urlresolvers import reverse
  20. from django.db import IntegrityError
  21. from distro_tracker.core.models import Subscription, EmailSettings
  22. from distro_tracker.core.models import PackageName, BinaryPackageName
  23. from distro_tracker.core.models import BinaryPackage
  24. from distro_tracker.core.models import Architecture
  25. from distro_tracker.core.models import BinaryPackageRepositoryEntry
  26. from distro_tracker.core.models import SourcePackageName
  27. from distro_tracker.core.models import SourcePackageRepositoryEntry
  28. from distro_tracker.core.models import Keyword
  29. from distro_tracker.core.models import ActionItem, ActionItemType
  30. from distro_tracker.core.models import PseudoPackageName
  31. from distro_tracker.core.models import Repository
  32. from distro_tracker.core.models import RepositoryFlag
  33. from distro_tracker.core.models import RepositoryRelation
  34. from distro_tracker.core.models import News
  35. from distro_tracker.core.models import EmailNews
  36. from distro_tracker.core.models import EmailNewsRenderer
  37. from distro_tracker.core.models import SourcePackage
  38. from distro_tracker.core.models import ExtractedSourceFile
  39. from distro_tracker.core.models import MailingList
  40. from distro_tracker.core.models import Team
  41. from distro_tracker.core.models import TeamMembership
  42. from distro_tracker.core.models import MembershipPackageSpecifics
  43. from distro_tracker.core.utils import message_from_bytes
  44. from distro_tracker.core.utils.email_messages import get_decoded_message_payload
  45. from distro_tracker.accounts.models import User, UserEmail
  46. from distro_tracker.test.utils import create_source_package
  47. import email
  48. import itertools
  49. class SubscriptionManagerTest(TestCase):
  50. def setUp(self):
  51. self.package = PackageName.objects.create(name='dummy-package')
  52. self.user_email = UserEmail.objects.create(email='email@domain.com')
  53. self.email_settings = \
  54. EmailSettings.objects.create(user_email=self.user_email)
  55. def create_subscription(self, package, email, active=True):
  56. """
  57. Helper method which creates a subscription for the given user to the
  58. given package.
  59. """
  60. return Subscription.objects.create_for(
  61. package_name=package,
  62. email=email,
  63. active=active)
  64. def test_create_for_existing_email(self):
  65. subscription = self.create_subscription(
  66. self.package.name, self.user_email.email)
  67. self.assertEqual(subscription.email_settings.user_email,
  68. self.user_email)
  69. self.assertEqual(subscription.package, self.package)
  70. self.assertIn(self.email_settings, self.package.subscriptions.all())
  71. self.assertTrue(subscription.active)
  72. def test_create_for_existing_email_inactive(self):
  73. """
  74. Tests the create_for method when creating an inactive subscription.
  75. """
  76. subscription = self.create_subscription(
  77. self.package.name, self.user_email.email, active=False)
  78. self.assertEqual(subscription.email_settings, self.email_settings)
  79. self.assertEqual(subscription.package, self.package)
  80. self.assertIn(self.email_settings, self.package.subscriptions.all())
  81. self.assertFalse(subscription.active)
  82. def test_create_for_unexisting_email(self):
  83. previous_count = UserEmail.objects.count()
  84. subscription = Subscription.objects.create_for(
  85. package_name=self.package.name,
  86. email='non-existing@email.com')
  87. self.assertEqual(UserEmail.objects.count(), previous_count + 1)
  88. self.assertEqual(subscription.package, self.package)
  89. self.assertTrue(subscription.active)
  90. def test_create_for_twice(self):
  91. """
  92. Tests that the create_for method creates only one Subscription for a
  93. user, package pair.
  94. """
  95. prev_cnt_subs = Subscription.objects.count()
  96. self.create_subscription(self.package.name, self.user_email.email)
  97. self.create_subscription(self.package.name, self.user_email.email)
  98. self.assertEqual(Subscription.objects.count(), prev_cnt_subs + 1)
  99. def test_get_for_email(self):
  100. """
  101. Tests the get_for_email method when the user is subscribed to multiple
  102. packages.
  103. """
  104. self.create_subscription(self.package.name, self.user_email.email)
  105. p = PackageName.objects.create(name='temp')
  106. self.create_subscription(p.name, self.user_email.email)
  107. package_not_subscribed_to = PackageName.objects.create(name='qwer')
  108. self.create_subscription(package_not_subscribed_to.name,
  109. self.user_email.email,
  110. active=False)
  111. l = Subscription.objects.get_for_email(self.user_email.email)
  112. l = [sub.package for sub in l]
  113. self.assertIn(self.package, l)
  114. self.assertIn(p, l)
  115. self.assertNotIn(package_not_subscribed_to, l)
  116. def test_get_for_email_no_subsriptions(self):
  117. """
  118. Tests the get_for_email method when the user is not subscribed to any
  119. packages.
  120. """
  121. l = Subscription.objects.get_for_email(self.user_email.email)
  122. self.assertEqual(len(l), 0)
  123. def test_all_active(self):
  124. active_subs = [
  125. self.create_subscription(self.package.name, self.user_email.email),
  126. self.create_subscription(self.package.name, 'email@d.com')
  127. ]
  128. inactive_subs = [
  129. self.create_subscription(self.package.name, 'email2@d.com', False),
  130. self.create_subscription(self.package.name, 'email3@d.com', False),
  131. ]
  132. for active in active_subs:
  133. self.assertIn(active, Subscription.objects.all_active())
  134. for inactive in inactive_subs:
  135. self.assertNotIn(inactive, Subscription.objects.all_active())
  136. def test_all_active_filter_keyword(self):
  137. """
  138. Tests the all_active method when it should filter based on a keyword
  139. """
  140. active_subs = [
  141. self.create_subscription(self.package.name, self.user_email.email),
  142. self.create_subscription(self.package.name, 'email1@a.com')
  143. ]
  144. sub_no_kw = self.create_subscription(self.package.name, 'email2@a.com')
  145. for active in active_subs:
  146. active.keywords.add(Keyword.objects.get_or_create(name='cvs')[0])
  147. sub_no_kw.keywords.remove(Keyword.objects.get(name='cvs'))
  148. inactive_subs = [
  149. self.create_subscription(self.package.name, 'email2@d.com', False),
  150. self.create_subscription(self.package.name, 'email3@d.com', False),
  151. ]
  152. for active in active_subs:
  153. self.assertIn(active, Subscription.objects.all_active('cvs'))
  154. self.assertNotIn(sub_no_kw, Subscription.objects.all_active('cvs'))
  155. for inactive in inactive_subs:
  156. self.assertNotIn(inactive, Subscription.objects.all_active('cvs'))
  157. class KeywordsTest(TestCase):
  158. def setUp(self):
  159. self.package = PackageName.objects.create(name='dummy-package')
  160. self.user_email = UserEmail.objects.create(email='email@domain.com')
  161. self.email_settings = \
  162. EmailSettings.objects.create(user_email=self.user_email)
  163. Keyword.objects.all().delete()
  164. self.email_settings.default_keywords.add(
  165. Keyword.objects.get_or_create(name='cvs')[0])
  166. self.email_settings.default_keywords.add(
  167. Keyword.objects.get_or_create(name='bts')[0])
  168. self.subscription = Subscription.objects.create(
  169. package=self.package,
  170. email_settings=self.email_settings)
  171. self.new_keyword = Keyword.objects.create(name='new')
  172. def test_keywords_add_to_subscription(self):
  173. """
  174. Test adding a new keyword to the subscription.
  175. """
  176. self.subscription.keywords.add(self.new_keyword)
  177. self.assertIn(self.new_keyword, self.subscription.keywords.all())
  178. self.assertNotIn(
  179. self.new_keyword, self.email_settings.default_keywords.all())
  180. for keyword in self.email_settings.default_keywords.all():
  181. self.assertIn(keyword, self.subscription.keywords.all())
  182. def test_keywords_remove_from_subscription(self):
  183. """
  184. Tests removing a keyword from the subscription.
  185. """
  186. keyword = self.email_settings.default_keywords.all()[0]
  187. self.subscription.keywords.remove(keyword)
  188. self.assertNotIn(keyword, self.subscription.keywords.all())
  189. self.assertIn(keyword, self.email_settings.default_keywords.all())
  190. def test_get_keywords_when_default(self):
  191. """
  192. Tests that the subscription uses the user's default keywords if none
  193. have explicitly been set for the subscription.
  194. """
  195. self.assertEqual(len(self.email_settings.default_keywords.all()),
  196. len(self.subscription.keywords.all()))
  197. self.assertEqual(self.email_settings.default_keywords.count(),
  198. self.subscription.keywords.count())
  199. for kw1, kw2 in zip(self.email_settings.default_keywords.all(),
  200. self.subscription.keywords.all()):
  201. self.assertEqual(kw1, kw2)
  202. class UserEmailTest(TestCase):
  203. def setUp(self):
  204. self.package = PackageName.objects.create(name='dummy-package')
  205. self.user_email = UserEmail.objects.create(email='email@domain.com')
  206. self.email_settings = \
  207. EmailSettings.objects.create(user_email=self.user_email)
  208. def test_is_subscribed_to(self):
  209. """
  210. Tests that the is_subscribed_to method returns True when the user is
  211. subscribed to a package.
  212. """
  213. Subscription.objects.create_for(
  214. package_name=self.package.name,
  215. email=self.user_email.email)
  216. self.assertTrue(
  217. self.user_email.emailsettings.is_subscribed_to(self.package))
  218. self.assertTrue(
  219. self.user_email.emailsettings.is_subscribed_to(self.package.name))
  220. def test_is_subscribed_to_false(self):
  221. """
  222. Tests that the ``is_subscribed_to`` method returns False when the user
  223. is not subscribed to the package.
  224. """
  225. self.assertFalse(
  226. self.user_email.emailsettings.is_subscribed_to(self.package))
  227. self.assertFalse(
  228. self.user_email.emailsettings.is_subscribed_to(self.package.name))
  229. def test_is_subscribed_to_false_inactive(self):
  230. """
  231. Tests that the ``is_subscribed_to`` method returns False when the user
  232. has not confirmed the subscription (the subscription is inactive)
  233. """
  234. Subscription.objects.create_for(
  235. package_name=self.package.name,
  236. email=self.user_email.email,
  237. active=False)
  238. self.assertFalse(
  239. self.user_email.emailsettings.is_subscribed_to(self.package))
  240. def test_is_subscribed_to_false_on_non_existing_package(self):
  241. """
  242. Tests that the ``is_subscribed_to`` method returns False when we
  243. query about a non-existing package.
  244. """
  245. self.assertFalse(
  246. self.user_email.emailsettings.is_subscribed_to('does-not-exist'))
  247. def test_new_user_has_default_keywords(self):
  248. """
  249. Tests that newly created users always have all the default keywords.
  250. """
  251. all_default_keywords = Keyword.objects.filter(default=True)
  252. self.assertEqual(self.email_settings.default_keywords.count(),
  253. all_default_keywords.count())
  254. for keyword in self.email_settings.default_keywords.all():
  255. self.assertIn(keyword, all_default_keywords)
  256. def test_unsubscribe_all(self):
  257. """
  258. Tests the unsubscribe all method.
  259. """
  260. Subscription.objects.create(email_settings=self.email_settings,
  261. package=self.package)
  262. self.user_email.emailsettings.unsubscribe_all()
  263. self.assertEqual(self.email_settings.subscription_set.count(), 0)
  264. class UserEmailManagerTest(TestCase):
  265. def setUp(self):
  266. self.package = PackageName.objects.create(name='dummy-package')
  267. self.user_email = UserEmail.objects.create(email='email@domain.com')
  268. self.email_settings = \
  269. EmailSettings.objects.create(user_email=self.user_email)
  270. def test_is_subscribed_to(self):
  271. """
  272. Tests that the is_subscribed_to method returns True when the
  273. user is subscribed to the given package.
  274. """
  275. Subscription.objects.create_for(
  276. package_name=self.package.name,
  277. email=self.user_email.email)
  278. self.assertTrue(
  279. self.user_email.emailsettings.is_subscribed_to(self.package.name))
  280. def test_is_subscribed_to_false(self):
  281. """
  282. Tests that the is_subscribed_to method returns False when the
  283. user is not subscribed to the given package.
  284. """
  285. self.assertFalse(
  286. self.user_email.emailsettings.is_subscribed_to(self.package.name))
  287. def test_is_subscribed_to_user_doesnt_exist(self):
  288. """
  289. Tests that the is_subscribed_to method returns False when the
  290. given user does not exist.
  291. """
  292. self.assertFalse(
  293. self.user_email.emailsettings.is_subscribed_to('unknown-package'))
  294. def test_is_subscribed_to_package_doesnt_exist(self):
  295. """
  296. Tests that the is_subscribed_to method returns False when the
  297. given package does not exist.
  298. """
  299. self.assertFalse(
  300. self.user_email.emailsettings.is_subscribed_to('unknown-package'))
  301. class PackageManagerTest(TestCase):
  302. def setUp(self):
  303. self.package = PackageName.objects.create(
  304. source=True,
  305. name='dummy-package')
  306. def test_package_create_fails_on_bad_package_name(self):
  307. with self.assertRaises(ValidationError):
  308. PackageName.objects.create(name='/../ b')
  309. def test_package_exists(self):
  310. self.assertTrue(PackageName.objects.exists_with_name(self.package.name))
  311. def test_package_exists_false(self):
  312. self.assertFalse(PackageName.objects.exists_with_name('unexisting'))
  313. def test_source_package_create(self):
  314. """
  315. Tests that the sources manager creates source packages.
  316. """
  317. p = PackageName.source_packages.create(name='source-package')
  318. self.assertTrue(p.source)
  319. self.assertFalse(p.binary)
  320. self.assertFalse(p.pseudo)
  321. def test_create_same_name_different_types_packages(self):
  322. """
  323. When several packages with different types and the same name are
  324. created, the 1st should create a package and the 2nd one should
  325. just update the corresponding “type” field (source, binary,
  326. pseudo).
  327. """
  328. # Package created without any type
  329. p, c = PackageName.objects.get_or_create(name='3-times-pkg')
  330. self.assertTrue(c)
  331. self.assertFalse(p.source or p.binary or p.pseudo)
  332. assert isinstance(p, PackageName)
  333. # Package does not exist as a source so believed to be created
  334. p, c = SourcePackageName.objects.get_or_create(name='3-times-pkg')
  335. self.assertTrue(c and p.source)
  336. self.assertFalse(p.binary or p.pseudo)
  337. assert isinstance(p, SourcePackageName)
  338. # Package exists as a source so should be seen as not created
  339. p, c = SourcePackageName.objects.get_or_create(name='3-times-pkg')
  340. self.assertTrue(p.source)
  341. self.assertFalse(c or p.binary or p.pseudo)
  342. assert isinstance(p, SourcePackageName)
  343. # Package does not exist as a binary so believed to be created
  344. p, c = BinaryPackageName.objects.get_or_create(name='3-times-pkg')
  345. self.assertTrue(c and p.source and p.binary)
  346. self.assertFalse(p.pseudo)
  347. assert isinstance(p, BinaryPackageName)
  348. # Package does not exist as a pseudo package so believed to be created
  349. p, c = PseudoPackageName.objects.get_or_create(name='3-times-pkg')
  350. self.assertTrue(c and p.source and p.binary and p.pseudo)
  351. assert isinstance(p, PseudoPackageName)
  352. def _test_package_name_proxy_delete_generic(self, proxy_class, pkg_type,
  353. multiple):
  354. """
  355. Generic function to test the deletion via a proxy class
  356. of PackageName.
  357. """
  358. p, c = proxy_class.objects.get_or_create(name='to-delete')
  359. self.assertTrue(getattr(p, pkg_type))
  360. if multiple:
  361. p.source = p.binary = p.pseudo = True
  362. p.save()
  363. p.delete()
  364. with self.assertRaises(ObjectDoesNotExist):
  365. proxy_class.objects.get(name='to-delete')
  366. p = PackageName.objects.get(name='to-delete')
  367. # The type field associated to the proxy class has been reset to False
  368. self.assertFalse(getattr(p, pkg_type))
  369. # The other type fields are left unchanged (False by default, True
  370. # if multiple)
  371. other_attributes = set(['source', 'binary', 'pseudo']) - set([pkg_type])
  372. for attribute in other_attributes:
  373. self.assertEqual(getattr(p, attribute), multiple)
  374. def _test_package_name_proxy_delete(self, proxy_class, pkg_type):
  375. self._test_package_name_proxy_delete_generic(proxy_class,
  376. pkg_type, False)
  377. self._test_package_name_proxy_delete_generic(proxy_class,
  378. pkg_type, True)
  379. def test_source_package_name_delete(self):
  380. """
  381. Ensure SourcePackageName doesn't really delete the underlying
  382. PackageName but resets the 'source' field instead.
  383. """
  384. self._test_package_name_proxy_delete(SourcePackageName, 'source')
  385. def _test_package_name_proxy_bulk_delete(self, proxy_class):
  386. """
  387. Ensure bulk delete via proxy class of PackageName doesn't really
  388. delete but resets the associated type field.
  389. """
  390. i = 0
  391. for source, binary, pseudo in \
  392. itertools.product([True, False], [True, False], [True, False]):
  393. PackageName.objects.create(name='to-delete-{0}'.format(i),
  394. source=source, binary=binary,
  395. pseudo=pseudo)
  396. i = i + 1
  397. p = proxy_class.objects.filter(name__startswith="to-delete-")
  398. p.delete()
  399. for i in range(0, 8):
  400. with self.assertRaises(ObjectDoesNotExist):
  401. proxy_class.objects.get(name="to-delete-{0}".format(i))
  402. # Counting packages left, should be 8 (packages are not really deleted
  403. # via proxy classes. Real delete is only made using PackageName class)
  404. p = PackageName.objects.filter(name__startswith="to-delete-").count()
  405. self.assertEqual(p, 8)
  406. def test_source_package_name_bulk_delete(self):
  407. """
  408. Ensure SourcePackageName's bulk delete doesn't really delete the
  409. underlying PackageName but resets the 'source' field instead.
  410. """
  411. self._test_package_name_proxy_bulk_delete(SourcePackageName)
  412. def test_pseudo_package_create(self):
  413. """
  414. Tests that the pseudo packages manager creates pseudo pacakges.
  415. """
  416. p = PackageName.pseudo_packages.create(name='pseudo-package')
  417. self.assertFalse(p.source)
  418. self.assertFalse(p.binary)
  419. self.assertTrue(p.pseudo)
  420. def test_pseudo_package_name_delete(self):
  421. """
  422. Ensure PseudoPackageName doesn't really delete the underlying
  423. PackageName but resets the 'pseudo' field instead.
  424. """
  425. self._test_package_name_proxy_delete(PseudoPackageName, 'pseudo')
  426. def test_pseudo_package_bulk_delete(self):
  427. """
  428. Ensure PseudoPackageName's bulk delete doesn't really delete the
  429. underlying PackageName but resets the 'pseudo' field instead.
  430. """
  431. self._test_package_name_proxy_bulk_delete(PseudoPackageName)
  432. def test_subscription_only_package_create(self):
  433. """
  434. Tests that the subscription only packages manager creates
  435. subscription only packages.
  436. """
  437. p = PackageName.objects.create(name='package')
  438. self.assertFalse(p.source)
  439. self.assertFalse(p.binary)
  440. self.assertFalse(p.pseudo)
  441. def test_binary_package_create(self):
  442. p = PackageName.binary_packages.create(name='pkg')
  443. self.assertFalse(p.source)
  444. self.assertTrue(p.binary)
  445. self.assertFalse(p.pseudo)
  446. def test_binary_package_name_delete(self):
  447. """
  448. Ensure BinaryPackageName doesn't really delete the underlying
  449. PackageName but resets the 'binary' field instead.
  450. """
  451. self._test_package_name_proxy_delete(BinaryPackageName, 'binary')
  452. def test_binary_package_name_bulk_delete(self):
  453. """
  454. Ensure BinaryPackageName's bulk delete doesn't really delete the
  455. underlying PackageName but resets the 'binary' field instead.
  456. """
  457. self._test_package_name_proxy_bulk_delete(BinaryPackageName)
  458. def test_manager_types_correct_objects(self):
  459. """
  460. Tests that the different manager types always return only their
  461. associated package type.
  462. """
  463. # Make sure there are no packages in the beginning
  464. PackageName.objects.all().delete()
  465. self.assertEqual(PackageName.objects.count(), 0)
  466. src_pkg = PackageName.source_packages.create(name='source-package')
  467. pseudo_pkg = PackageName.pseudo_packages.create(name='pseudo-package')
  468. PackageName.objects.create(name='package')
  469. # objects manager returns all packages
  470. self.assertEqual(PackageName.objects.count(), 3)
  471. # specific pacakge type managers:
  472. self.assertEqual(PackageName.source_packages.count(), 1)
  473. self.assertIn(src_pkg, PackageName.source_packages.all())
  474. self.assertEqual(PackageName.pseudo_packages.count(), 1)
  475. self.assertIn(pseudo_pkg, PackageName.pseudo_packages.all())
  476. def test_all_with_subscriptions(self):
  477. """
  478. Tests the manager method which should return a QuerySet with all
  479. packages that have at least one subscriber.
  480. """
  481. pseudo_package = PseudoPackageName.objects.create(name='pseudo-package')
  482. sub_only_pkg = PackageName.objects.create(
  483. name='sub-only-pkg')
  484. PackageName.objects.create(name='sub-only-pkg-1')
  485. # When there are no subscriptions, it shouldn't return any results
  486. self.assertEqual(PackageName.objects.all_with_subscribers().count(), 0)
  487. self.assertEqual(
  488. PackageName.pseudo_packages.all_with_subscribers().count(),
  489. 0)
  490. self.assertEqual(
  491. PackageName.source_packages.all_with_subscribers().count(),
  492. 0)
  493. # When subscriptions are added, only the packages with subscriptions
  494. # are returned
  495. Subscription.objects.create_for(package_name=self.package.name,
  496. email='user@domain.com')
  497. Subscription.objects.create_for(package_name=sub_only_pkg.name,
  498. email='other-user@domain.com')
  499. Subscription.objects.create_for(package_name=pseudo_package.name,
  500. email='some-user@domain.com')
  501. self.assertEqual(PackageName.objects.all_with_subscribers().count(), 3)
  502. all_with_subscribers = [
  503. pkg.name
  504. for pkg in PackageName.objects.all_with_subscribers()
  505. ]
  506. self.assertIn(self.package.name, all_with_subscribers)
  507. self.assertIn(pseudo_package.name, all_with_subscribers)
  508. self.assertIn(sub_only_pkg.name, all_with_subscribers)
  509. # Specific managers...
  510. self.assertEqual(
  511. PackageName.pseudo_packages.all_with_subscribers().count(),
  512. 1)
  513. self.assertEqual(
  514. PackageName.source_packages.all_with_subscribers().count(),
  515. 1)
  516. class BinaryPackageManagerTest(TestCase):
  517. def setUp(self):
  518. self.package = SourcePackageName.objects.create(name='dummy-package')
  519. self.binary_package = BinaryPackageName.objects.create(
  520. name='binary-package')
  521. def test_package_exists(self):
  522. self.assertTrue(BinaryPackageName.objects.exists_with_name(
  523. self.binary_package.name))
  524. def test_package_exists_false(self):
  525. self.assertFalse(
  526. BinaryPackageName.objects.exists_with_name('unexisting'))
  527. class RepositoryTests(TestCase):
  528. fixtures = ['repository-test-fixture.json']
  529. def setUp(self):
  530. self.repository = Repository.objects.all()[0]
  531. self.src_pkg_name = \
  532. SourcePackageName.objects.create(name='dummy-package')
  533. self.source_package = SourcePackage.objects.create(
  534. source_package_name=self.src_pkg_name, version='1.0.0')
  535. self.bin_pkg_name = PackageName.objects.get(name='dummy-package')
  536. self.bin_pkg_name.binary = True
  537. self.bin_pkg_name.save()
  538. self.bin_pkg_name = BinaryPackageName.objects.get(name='dummy-package')
  539. self.binary_package = BinaryPackage.objects.create(
  540. binary_package_name=self.bin_pkg_name,
  541. version='1.0.0',
  542. source_package=self.source_package)
  543. self.repo1 = Repository.objects.create(
  544. name='repo1', shorthand='repo1', codename='codename1',
  545. suite='suite1')
  546. self.repo2 = Repository.objects.create(
  547. name='repo2', shorthand='repo2', codename='codename2',
  548. suite='suite2')
  549. def test_add_source_entry_to_repository(self):
  550. """
  551. Tests adding a source package entry (name, version) to a repository
  552. instance.
  553. """
  554. self.repository.add_source_package(self.source_package)
  555. # An entry is created.
  556. self.assertEqual(SourcePackageRepositoryEntry.objects.count(), 1)
  557. e = SourcePackageRepositoryEntry.objects.all()[0]
  558. # Correct source package
  559. self.assertEqual(e.source_package, self.source_package)
  560. # Correct repository
  561. self.assertEqual(e.repository, self.repository)
  562. def test_add_binary_entry_to_repository(self):
  563. """
  564. Tests adding a new binary package entry (name, version) to a repository
  565. instance.
  566. """
  567. architecture = Architecture.objects.all()[0]
  568. self.repository.add_binary_package(
  569. self.binary_package,
  570. architecture=architecture)
  571. # An entry is created
  572. self.assertEqual(1, BinaryPackageRepositoryEntry.objects.count())
  573. e = BinaryPackageRepositoryEntry.objects.all()[0]
  574. # Correct binary package
  575. self.assertEqual(self.binary_package, e.binary_package)
  576. # Correct repository
  577. self.assertEqual(self.repository, e.repository)
  578. def test_add_source_entry_to_repository_extra_info(self):
  579. """
  580. Tests adding a source package entry (name, version + repository
  581. specific information) to a repository instance.
  582. """
  583. self.repository.add_source_package(self.source_package, **{
  584. 'priority': 'source',
  585. 'section': 'admin',
  586. })
  587. # An entry is created.
  588. self.assertEqual(SourcePackageRepositoryEntry.objects.count(), 1)
  589. e = SourcePackageRepositoryEntry.objects.all()[0]
  590. # Correct source package
  591. self.assertEqual(e.source_package, self.source_package)
  592. # Correct repository
  593. self.assertEqual(e.repository, self.repository)
  594. # Extra (repository-specific data is saved)
  595. self.assertEqual(e.priority, 'source')
  596. self.assertEqual(e.section, 'admin')
  597. def test_has_source_package_name_1(self):
  598. """
  599. Tests the has_source_package_name when the given source package is
  600. found in the repository.
  601. """
  602. self.repository.add_source_package(self.source_package)
  603. self.assertTrue(
  604. self.repository.has_source_package_name(self.source_package.name))
  605. def test_has_source_package_name_2(self):
  606. """
  607. Tests the has_source_package_name when the given source package is
  608. found in the repository.
  609. """
  610. self.repository.add_source_package(self.source_package)
  611. source_package = SourcePackage.objects.create(
  612. source_package_name=self.src_pkg_name, version='1.2.0')
  613. # Add another version of the same package
  614. self.repository.add_source_package(source_package)
  615. self.assertTrue(
  616. self.repository.has_source_package_name(self.source_package.name))
  617. def test_has_source_package_name_3(self):
  618. """
  619. Tests the has_source_package_name when the given source package is not
  620. found in the repository.
  621. """
  622. self.assertFalse(
  623. self.repository.has_source_package_name(self.source_package.name))
  624. def test_has_source_package_name_does_not_exist(self):
  625. """
  626. Tests the has_source_package_name when the given source package name
  627. does not exist.
  628. """
  629. # Sanity check - the package really does not exist
  630. self.assertFalse(
  631. SourcePackageName.objects.filter(name='no-exist').exists())
  632. self.assertFalse(
  633. self.repository.has_source_package_name('no-exist'))
  634. def test_has_source_package_1(self):
  635. """
  636. Tests the has_source_package when the given source package is found in
  637. the repository.
  638. """
  639. self.repository.add_source_package(self.source_package)
  640. self.assertTrue(
  641. self.repository.has_source_package(self.source_package))
  642. def test_has_source_package_2(self):
  643. """
  644. Tests the has_source_package when the given source package is not found
  645. in the repository.
  646. """
  647. self.assertFalse(
  648. self.repository.has_source_package(self.source_package))
  649. def test_get_source_package_repository_entry_single(self):
  650. """
  651. Tests the
  652. :meth:`get_source_package_entry
  653. <distro_tracker.core.models.Repository.get_source_package_entry>` method
  654. when there is only one version of the given package in the repository.
  655. """
  656. entry = self.repository.add_source_package(self.source_package)
  657. # When passing a SourcePackageName
  658. self.assertEqual(
  659. self.repository.get_source_package_entry(
  660. self.source_package.source_package_name),
  661. entry)
  662. # When passing a string
  663. self.assertEqual(
  664. self.repository.get_source_package_entry(
  665. self.source_package.source_package_name.name),
  666. entry)
  667. def test_get_source_package_repository_entry_multiple(self):
  668. """
  669. Tests the
  670. :meth:`get_source_package_entry
  671. <distro_tracker.core.models.Repository.get_source_package_entry>` method
  672. when there are multiple versions of the given package in the repository.
  673. """
  674. higher_version_package = SourcePackage.objects.create(
  675. source_package_name=self.src_pkg_name, version='2.0.0')
  676. self.repository.add_source_package(self.source_package)
  677. expected_entry = self.repository.add_source_package(
  678. higher_version_package)
  679. # When passing a SourcePackageName
  680. self.assertEqual(
  681. self.repository.get_source_package_entry(
  682. self.source_package.source_package_name),
  683. expected_entry)
  684. # When passing a string
  685. self.assertEqual(
  686. self.repository.get_source_package_entry(
  687. self.source_package.source_package_name.name),
  688. expected_entry)
  689. def test_is_development_repository_default_case(self):
  690. """We have not provided any explicit list of development repositories.
  691. The default repository is the only development repository."""
  692. self.assertTrue(self.repository.is_development_repository())
  693. self.assertFalse(self.repo1.is_development_repository())
  694. self.assertFalse(self.repo2.is_development_repository())
  695. @override_settings(
  696. DISTRO_TRACKER_DEVEL_REPOSITORIES=['suite1', 'codename2'])
  697. def test_is_development_repository_explicit_list(self):
  698. """We have provided an explicit list of development repositories. It
  699. should be the reference."""
  700. self.assertFalse(self.repository.is_development_repository())
  701. self.assertTrue(self.repo1.is_development_repository())
  702. self.assertTrue(self.repo2.is_development_repository())
  703. class RepositoryFlagsTests(TestCase):
  704. def setUp(self):
  705. self.repo1 = Repository.objects.create(
  706. name='repo1', shorthand='repo1', codename='codename1',
  707. suite='suite1')
  708. def test_add_flags(self):
  709. """
  710. Test adding a flag to a repository and accessing to the flag via
  711. the repository
  712. """
  713. self.repo_flag = RepositoryFlag.objects.create(
  714. repository=self.repo1, name='hidden', value=True)
  715. self.assertEqual(self.repo_flag, self.repo1.flags.first())
  716. def test_unique_keys(self):
  717. """
  718. Test that we can't create two identic flags for the same repository
  719. """
  720. self.repo_flag = RepositoryFlag.objects.create(
  721. repository=self.repo1, name='hidden', value=True)
  722. with self.assertRaises(IntegrityError):
  723. RepositoryFlag.objects.create(repository=self.repo1, name='hidden',
  724. value=True)
  725. def test_get_flags_existing(self):
  726. """Ensure Repository.get_flags() returns existing flags"""
  727. self.repo1.flags.create(name='testflag', value=True)
  728. self.repo1.flags.create(name='testflag2', value=False)
  729. flags = self.repo1.get_flags()
  730. self.assertEqual(flags['testflag'], True)
  731. self.assertEqual(flags['testflag2'], False)
  732. def test_get_flags_non_existing(self):
  733. """Ensure Repository.get_flags() returns default values for
  734. non-existing flags"""
  735. flags = self.repo1.get_flags()
  736. for flag, defvalue in RepositoryFlag.FLAG_DEFAULT_VALUES.items():
  737. self.assertEqual(flags[flag], defvalue)
  738. def test_get_flags_existing_non_default_value(self):
  739. """Ensure get_flags() returns the value of the RepositoryFlag
  740. and not only the default value of the flag"""
  741. for flag, defvalue in RepositoryFlag.FLAG_DEFAULT_VALUES.items():
  742. self.repo1.flags.create(name=flag, value=not defvalue)
  743. flags = self.repo1.get_flags()
  744. for flag, defvalue in RepositoryFlag.FLAG_DEFAULT_VALUES.items():
  745. self.assertEqual(flags[flag], not defvalue)
  746. class RepositoryRelationTests(TestCase):
  747. def setUp(self):
  748. self.repo1 = Repository.objects.create(
  749. name='repo1', shorthand='repo1', codename='codename1',
  750. suite='suite1')
  751. self.repo2 = Repository.objects.create(
  752. name='repo2', shorthand='repo2', codename='codename2',
  753. suite='suite2')
  754. self.repo3 = Repository.objects.create(
  755. name='repo3', shorthand='repo3', codename='codename3',
  756. suite='suite3')
  757. def test_add_relation(self):
  758. """
  759. Test adding a relation between two repositories and acessing to the
  760. relation information.
  761. """
  762. repo_relation = RepositoryRelation.objects.create(
  763. repository=self.repo1,
  764. target_repository=self.repo2,
  765. name='derivative')
  766. self.assertEqual(repo_relation, self.repo1.relations.first())
  767. self.assertEqual(repo_relation, self.repo2.reverse_relations.first())
  768. def test_unique_keys(self):
  769. """
  770. Test that we can't create two identic relations for the same repository.
  771. """
  772. RepositoryRelation.objects.create(repository=self.repo1,
  773. target_repository=self.repo2,
  774. name='derivative')
  775. with self.assertRaises(IntegrityError):
  776. RepositoryRelation.objects.create(
  777. repository=self.repo1, target_repository=self.repo3,
  778. name='derivative')
  779. class SourcePackageTests(TestCase):
  780. fixtures = ['repository-test-fixture.json']
  781. def setUp(self):
  782. self.repository = Repository.objects.all()[0]
  783. self.src_pkg_name = \
  784. SourcePackageName.objects.create(name='dummy-package')
  785. self.source_package = SourcePackage.objects.create(
  786. source_package_name=self.src_pkg_name, version='1.0.0')
  787. def test_main_version_1(self):
  788. """
  789. Tests that the main version is correctly returned when the package is
  790. found in only one repository.
  791. """
  792. self.repository.add_source_package(self.source_package)
  793. self.assertEqual(self.source_package, self.src_pkg_name.main_version)
  794. def test_main_version_2(self):
  795. """
  796. Tests that the main version is correctly returned when the package is
  797. found multiple times (with different versions) in the default
  798. repository.
  799. """
  800. self.repository.add_source_package(self.source_package)
  801. higher_version_pkg = SourcePackage.objects.create(
  802. source_package_name=self.src_pkg_name, version='10.0.0')
  803. self.repository.add_source_package(higher_version_pkg)
  804. self.assertEqual(higher_version_pkg, self.src_pkg_name.main_version)
  805. def test_main_version_3(self):
  806. """
  807. Test that the main version is correctly returned when the package is
  808. found in multiple repositories.
  809. """
  810. self.repository.add_source_package(self.source_package)
  811. higher_version_pkg = SourcePackage.objects.create(
  812. source_package_name=self.src_pkg_name, version='10.0.0')
  813. non_default_repository = Repository.objects.create(name='repo')
  814. non_default_repository.add_source_package(higher_version_pkg)
  815. # The main version is the one from the default repository, regardless
  816. # of the fact that it has a lower version number.
  817. self.assertEqual(self.source_package, self.src_pkg_name.main_version)
  818. def test_main_entry_1(self):
  819. """
  820. Tests that the main entry is correctly returned when the package is
  821. found in only one repository.
  822. """
  823. self.repository.add_source_package(self.source_package)
  824. expected = SourcePackageRepositoryEntry.objects.get(
  825. source_package=self.source_package, repository=self.repository)
  826. self.assertEqual(expected, self.src_pkg_name.main_entry)
  827. def test_main_entry_2(self):
  828. """
  829. Tests that the main entry is correctly returned when the package is
  830. found multiple times (with different versions) in the default
  831. repository.
  832. """
  833. self.repository.add_source_package(self.source_package)
  834. higher_version_pkg = SourcePackage.objects.create(
  835. source_package_name=self.src_pkg_name, version='10.0.0')
  836. self.repository.add_source_package(higher_version_pkg)
  837. expected = SourcePackageRepositoryEntry.objects.get(
  838. source_package=higher_version_pkg, repository=self.repository)
  839. self.assertEqual(expected, self.src_pkg_name.main_entry)
  840. def test_main_entry_3(self):
  841. """
  842. Tests that the main entry is correctly returned when the package is
  843. found in multiple repositories.
  844. """
  845. self.repository.add_source_package(self.source_package)
  846. higher_version_pkg = SourcePackage.objects.create(
  847. source_package_name=self.src_pkg_name, version='10.0.0')
  848. non_default_repository = Repository.objects.create(name='repo')
  849. non_default_repository.add_source_package(higher_version_pkg)
  850. expected = SourcePackageRepositoryEntry.objects.get(
  851. source_package=self.source_package, repository=self.repository)
  852. self.assertEqual(expected, self.src_pkg_name.main_entry)
  853. def test_get_directory_url(self):
  854. """
  855. Tests retrieving the URL of the package's directory from the entry.
  856. """
  857. architectures = ['amd64', 'all']
  858. src_pkg = create_source_package({
  859. 'name': 'package-with-directory',
  860. 'binary_packages': ['binary-package'],
  861. 'version': '0.1',
  862. 'maintainer': {
  863. 'name': 'Maintainer',
  864. 'email': 'maintainer@domain.com'
  865. },
  866. 'architectures': architectures,
  867. 'directory': 'pool/path/to/dir',
  868. })
  869. entry = self.repository.add_source_package(src_pkg)
  870. self.assertEqual(
  871. self.repository.uri + 'pool/path/to/dir',
  872. entry.directory_url
  873. )
  874. def test_get_directory_url_no_directory_set(self):
  875. """
  876. Tests retrieving the URL of the package's directory from the repository
  877. entry when no directory is set for the source package.
  878. """
  879. entry = self.repository.add_source_package(self.source_package)
  880. self.assertIsNone(entry.directory_url)
  881. def test_get_dsc_file_url(self):
  882. """
  883. Tests retrieving the URL of the package's .dsc file given in the entry.
  884. """
  885. architectures = ['amd64', 'all']
  886. src_pkg = create_source_package({
  887. 'name': 'package-with-dsc-file',
  888. 'binary_packages': ['binary-package'],
  889. 'version': '0.1',
  890. 'maintainer': {
  891. 'name': 'Maintainer',
  892. 'email': 'maintainer@domain.com'
  893. },
  894. 'architectures': architectures,
  895. 'directory': 'pool/path/to/dir',
  896. 'dsc_file_name': 'file.dsc',
  897. })
  898. entry = self.repository.add_source_package(src_pkg)
  899. self.assertEqual(
  900. self.repository.uri + 'pool/path/to/dir/file.dsc',
  901. entry.dsc_file_url
  902. )
  903. def test_get_dsc_file_url_no_file_set(self):
  904. """
  905. Tests retrieving the URL of the package's .dsc file given when there is
  906. no dsc file found in the source package information.
  907. """
  908. entry = self.repository.add_source_package(self.source_package)
  909. self.assertIsNone(entry.dsc_file_url)
  910. def test_get_version_entry_default_repo(self):
  911. """
  912. Tests that the
  913. :class:`SourcePackageRepositoryEntry
  914. <distro_tracker.core.models.SourcePackageRepositoryEntry>` matching the
  915. default repository is always returned from the
  916. :meth:`SourcePackage.main_entry
  917. <distro_tracker.core.models.SourcePackage.main_entry>` property.
  918. """
  919. # Make sure the repository is default
  920. self.repository.default = True
  921. self.repository.save()
  922. non_default_repository = Repository.objects.create(name='non-default')
  923. default_entry = self.repository.add_source_package(self.source_package)
  924. non_default_repository.add_source_package(self.source_package)
  925. self.assertEqual(self.source_package.main_entry, default_entry)
  926. def test_get_version_entry_non_default_repo(self):
  927. """
  928. Tests that the
  929. :class:`SourcePackageRepositoryEntry
  930. <distro_tracker.core.models.SourcePackageRepositoryEntry>` matching the
  931. repository with the highest :attr:`position
  932. <distro_tracker.core.models.Repository.position>` field is returned from
  933. :meth:`SourcePackage.main_entry
  934. <distro_tracker.core.models.SourcePackage.main_entry>` when the package
  935. is not found in the default repository.
  936. """
  937. self.repository.default = False
  938. self.repository.save()
  939. higher_position_repository = Repository.objects.create(
  940. name='higher-position', position=self.repository.position + 1)
  941. # Add the package to both repositories
  942. self.repository.add_source_package(self.source_package)
  943. expected_entry = higher_position_repository.add_source_package(
  944. self.source_package)
  945. self.assertEqual(self.source_package.main_entry, expected_entry)
  946. def test_get_version_entry_no_repo(self):
  947. """
  948. Tests that the :meth:`SourcePackage.main_entry
  949. <distro_tracker.core.models.SourcePackage.main_entry>` property returns
  950. ``None`` when the version is not found in any repository.
  951. """
  952. self.assertIsNone(self.source_package.main_entry)
  953. def test_changelog_entry_only(self):
  954. """
  955. Tests that the :meth:`get_changelog_entry
  956. <distro_tracker.core.models.SourcePackage.get_changelog_entry>` returns
  957. the changelog part correctly when it is the only entry in the changelog
  958. file.
  959. """
  960. changelog_entry = (
  961. "{pkg} ({ver}) suite; urgency=high\n\n"
  962. " * New stable release:\n"
  963. " - Feature 1\n"
  964. " - Feature 2\n\n"
  965. " -- Maintainer <email@domain.com> Mon, 1 July 2013 09:00:00 +0000"
  966. ).format(pkg=self.source_package.name, ver=self.source_package.version)
  967. changelog_content = changelog_entry
  968. ExtractedSourceFile.objects.create(
  969. source_package=self.source_package,
  970. extracted_file=ContentFile(changelog_content, name='changelog'),
  971. name='changelog')
  972. self.assertEqual(
  973. self.source_package.get_changelog_entry(),
  974. changelog_entry)
  975. def test_changelog_entry_beginning(self):
  976. """
  977. Tests that the :meth:`get_changelog_entry
  978. <distro_tracker.core.models.SourcePackage.get_changelog_entry>` returns
  979. the changelog part correctly when it is the latest entry in the
  980. changelog file.
  981. """
  982. changelog_entry = (
  983. "{pkg} ({ver}) suite; urgency=high\n\n"
  984. " * New stable release:\n"
  985. " - Feature 1\n"
  986. " - Feature 2\n\n"
  987. " -- Maintainer <email@domain.com> Mon, 1 July 2013 09:00:00 +0000"
  988. ).format(pkg=self.source_package.name, ver=self.source_package.version)
  989. other_content = (
  990. "{pkg} ({ver}) suite; urgency=high\n\n"
  991. " * New stable release:\n"
  992. " - Feature\n\n"
  993. " -- Maintainer <email@domain.com> Mon, 1 July 2013 09:00:00 +0000"
  994. ).format(pkg=self.source_package.name, ver='9.9.9')
  995. changelog_content = changelog_entry + '\n' + other_content
  996. ExtractedSourceFile.objects.create(
  997. source_package=self.source_package,
  998. extracted_file=ContentFile(changelog_content, name='changelog'),
  999. name='changelog')
  1000. self.assertEqual(
  1001. self.source_package.get_changelog_entry(),
  1002. changelog_entry)
  1003. def test_changelog_entry_not_first(self):
  1004. """
  1005. Tests that the :meth:`get_changelog_entry
  1006. <distro_tracker.core.models.SourcePackage.get_changelog_entry>` returns
  1007. the changelog part correctly when it is not the latest entry in the
  1008. changelog file.
  1009. """
  1010. changelog_entry = (
  1011. "{pkg} ({ver}) suite; urgency=high\n\n"
  1012. " * New stable release:\n"
  1013. " - Feature 1\n"
  1014. " - Feature 2\n\n"
  1015. " -- Maintainer <email@domain.com> Mon, 1 July 2013 09:00:00 +0000"
  1016. ).format(pkg=self.source_package.name, ver=self.source_package.version)
  1017. other_content = (
  1018. "{pkg} ({ver}) suite; urgency=high\n\n"
  1019. " * New stable release:\n"
  1020. " - Feature\n\n"
  1021. " -- Maintainer <email@domain.com> Mon, 1 July 2013 09:00:00 +0000"
  1022. ).format(pkg=self.source_package.name, ver='9.9.9')
  1023. changelog_content = other_content + '\n' + changelog_entry
  1024. ExtractedSourceFile.objects.create(
  1025. source_package=self.source_package,
  1026. extracted_file=ContentFile(changelog_content, name='changelog'),
  1027. name='changelog')
  1028. self.assertEqual(
  1029. self.source_package.get_changelog_entry(),
  1030. changelog_entry)
  1031. def test_changelog_entry_regex_meta_chars(self):
  1032. """
  1033. Tests that the :meth:`get_changelog_entry
  1034. <distro_tracker.core.models.SourcePackage.get_changelog_entry>` returns
  1035. the changelog part correctly when the version contains a regex meta
  1036. character.
  1037. """
  1038. self.source_package.version = self.source_package.version + '+deb7u1'
  1039. self.source_package.save()
  1040. changelog_entry = (
  1041. "{pkg} ({ver}) suite; urgency=high\n\n"
  1042. " * New stable release:\n"
  1043. " - Feature 1\n"
  1044. " - Feature 2\n\n"
  1045. " -- Maintainer <email@domain.com> Mon, 1 July 2013 09:00:00 +0000"
  1046. ).format(pkg=self.source_package.name, ver=self.source_package.version)
  1047. changelog_content = changelog_entry
  1048. ExtractedSourceFile.objects.create(
  1049. source_package=self.source_package,
  1050. extracted_file=ContentFile(changelog_content, name='changelog'),
  1051. name='changelog')
  1052. self.assertEqual(
  1053. self.source_package.get_changelog_entry(),
  1054. changelog_entry)
  1055. class BinaryPackageTests(TestCase):
  1056. fixtures = ['repository-test-fixture.json']
  1057. def setUp(self):
  1058. self.repository = Repository.objects.all()[0]
  1059. self.src_pkg_name = \
  1060. SourcePackageName.objects.create(name='dummy-package')
  1061. self.source_package = SourcePackage.objects.create(
  1062. source_package_name=self.src_pkg_name, version='1.0.0')
  1063. self.binary_package = BinaryPackageName.objects.create(
  1064. name='binary-package')
  1065. def test_binary_package_name_to_source_name_1(self):
  1066. """
  1067. Tests retrieving a source package name from a binary package name when
  1068. the binary package name is registered for only one source package.
  1069. """
  1070. self.source_package.binary_packages.add(self.binary_package)
  1071. self.assertEqual(
  1072. self.src_pkg_name,
  1073. self.binary_package.main_source_package_name
  1074. )
  1075. def test_binary_package_name_to_source_name_2(self):
  1076. """
  1077. Tests retrieving a source package name from a binary package name when
  1078. the binary package is registered for two different source packages
  1079. """
  1080. self.source_package.binary_packages.add(self.binary_package)
  1081. higher_version_name = SourcePackageName.objects.create(
  1082. name='higher-version-name')
  1083. higher_version_pkg = SourcePackage.objects.create(
  1084. source_package_name=higher_version_name, version='10.0.0')
  1085. higher_version_pkg.binary_packages.add(self.binary_package)
  1086. self.assertEqual(
  1087. higher_version_name,
  1088. self.binary_package.main_source_package_name
  1089. )
  1090. def test_binary_package_name_to_source_name_default_repository(self):
  1091. """
  1092. Tests retrieving a source package name from a binary package name when
  1093. the resulting source package name should be the one from the default
  1094. repository.
  1095. """
  1096. self.repository.add_source_package(self.source_package)
  1097. self.source_package.binary_packages.add(self.binary_package)
  1098. higher_version_name = SourcePackageName.objects.create(
  1099. name='higher-version-name')
  1100. higher_version_pkg = SourcePackage.objects.create(
  1101. source_package_name=higher_version_name, version='10.0.0')
  1102. # Add the higher version package to a non-default repository
  1103. non_default_repository = Repository.objects.create(name='repo')
  1104. non_default_repository.add_source_package(higher_version_pkg)
  1105. higher_version_pkg.binary_packages.add(self.binary_package)
  1106. # The resulting name is the name of the source package found in the
  1107. # default repository.
  1108. self.assertEqual(
  1109. self.src_pkg_name,
  1110. self.binary_package.main_source_package_name
  1111. )
  1112. class MailingListTest(TestCase):
  1113. def test_validate_url_template(self):
  1114. """
  1115. Tests validation of the URL template field.
  1116. """
  1117. mailing_list = MailingList(name='list', domain='some.domain.com')
  1118. mailing_list.archive_url_template = (
  1119. 'http://this.does/not/have/user/parameter')
  1120. with self.assertRaises(ValidationError):
  1121. mailing_list.full_clean()
  1122. mailing_list.archive_url_template = (
  1123. 'http://this.does/have/{user}')
  1124. mailing_list.full_clean()
  1125. def test_get_archive_url(self):
  1126. """
  1127. Tests retrieving the archive URL from a MailingList instance.
  1128. """
  1129. mailing_list = MailingList(name='list', domain='some.domain.com')
  1130. mailing_list.archive_url_template = (
  1131. 'http://some.domain.com/archive/{user}/')
  1132. self.assertEqual(
  1133. mailing_list.archive_url('this-is-a-user'),
  1134. 'http://some.domain.com/archive/this-is-a-user/'
  1135. )
  1136. def test_get_archive_url_for_email(self):
  1137. """
  1138. Test retrieving the archive URL from a MailingList instance when an
  1139. email is given, instead of a user.
  1140. """
  1141. mailing_list = MailingList(name='list', domain='some.domain.com')
  1142. mailing_list.archive_url_template = (
  1143. 'http://some.domain.com/archive/{user}/')
  1144. self.assertEqual(
  1145. mailing_list.archive_url_for_email(
  1146. 'this-is-a-user@some.domain.com'),
  1147. 'http://some.domain.com/archive/this-is-a-user/'
  1148. )
  1149. # Not given a valid email
  1150. self.assertIsNone(
  1151. mailing_list.archive_url_for_email('this-is-not-an-email'))
  1152. # Not given an email in the correct domain
  1153. self.assertIsNone(
  1154. mailing_list.archive_url_for_email('email@other.domain.com'))
  1155. def test_find_matching_mailing_list(self):
  1156. """
  1157. Tests finding a matching mailing list object when given an email.
  1158. """
  1159. expect = MailingList.objects.create(
  1160. name='list', domain='some.domain.com')
  1161. MailingList.objects.create(name='other', domain='other.com')
  1162. MailingList.objects.create(name='domain', domain='domain.com')
  1163. email = 'username@some.domain.com'
  1164. self.assertEqual(MailingList.objects.get_by_email(email), expect)
  1165. email = 'not-an-email'
  1166. self.assertIsNone(MailingList.objects.get_by_email(email))
  1167. email = 'user@no.registered.domain'
  1168. self.assertIsNone(MailingList.objects.get_by_email(email))
  1169. class NewsTests(TestCase):
  1170. """
  1171. Tests for the :class:`distro_tracker.core.models.News` model.
  1172. """
  1173. def setUp(self):
  1174. self.package = SourcePackageName.objects.create(name='dummy-package')
  1175. def test_content_from_db(self):
  1176. """
  1177. Tests that the :meth:`distro_tracker.core.models.News.content` property
  1178. returns the correct contents when they are found in the database.
  1179. """
  1180. expected_content = 'This is some news content'
  1181. news = News.objects.create(
  1182. title='some title',
  1183. _db_content=expected_content,
  1184. package=self.package
  1185. )
  1186. self.assertEqual(news.content, expected_content)
  1187. def test_content_from_file(self):
  1188. """
  1189. Tests that the :meth:`distro_tracker.core.models.News.content` property
  1190. returns the correct contents when they are found in a file.
  1191. """
  1192. expected_content = b'This is some news content'
  1193. # Create a temporary file for the content
  1194. content_file = ContentFile(expected_content, name='tmp-content')
  1195. # Create the news item with the given content file
  1196. news = News.objects.create(
  1197. title='some title',
  1198. package=self.package,
  1199. news_file=content_file
  1200. )
  1201. self.assertEqual(news.content, expected_content)
  1202. def test_no_content(self):
  1203. """
  1204. Tests that the :meth:`distro_tracker.core.models.News.content` property
  1205. returns no content when neither the database content nor file content is
  1206. set.
  1207. """
  1208. news = News.objects.create(title='some title', package=self.package)
  1209. self.assertIsNone(news.content)
  1210. def test_create_db_content(self):
  1211. """
  1212. Tests the :meth:`distro_tracker.core.models.NewsManager.create` method
  1213. when it should create an instance whose content is stored in the
  1214. database.
  1215. """
  1216. expected_content = 'Some content'
  1217. news = News.objects.create(
  1218. title='some title',
  1219. content=expected_content,
  1220. package=self.package)
  1221. self.assertEqual(news._db_content, expected_content)
  1222. self.assertFalse(news.news_file)
  1223. def test_create_file_content(self):
  1224. """
  1225. Tests the :meth:`distro_tracker.core.models.NewsManager.create` method
  1226. when it should create an instance whose content is stored in a file.
  1227. """
  1228. expected_content = b'Some content'
  1229. news = News.objects.create(
  1230. title='some title',
  1231. file_content=expected_content,
  1232. package=self.package)
  1233. self.assertTrue(news.news_file)
  1234. self.assertIsNone(news._db_content)
  1235. self.assertEqual(news.content, expected_content)
  1236. def test_create_email_news_signature(self):
  1237. """
  1238. Tests that the signature information is correctly extracted when
  1239. creating a news item from an email message which was transfer encoded
  1240. as quoted-printable.
  1241. """
  1242. self.import_key_into_keyring('key1.pub')
  1243. # The content of the test news item is found in a file
  1244. file_path = self.get_test_data_path(
  1245. 'signed-message-quoted-printable')
  1246. with open(file_path, 'rb') as f:
  1247. content = f.read()
  1248. expected_name = 'PTS Tests'
  1249. expected_email = 'fake-address@domain.com'
  1250. sender_name = 'Some User'
  1251. news = EmailNews.objects.create_email_news(
  1252. message=message_from_bytes(content),
  1253. package=self.package)
  1254. # The news contains a signature
  1255. self.assertEqual(1, news.signed_by.count())
  1256. # The signature information is correct?
  1257. signer = news.signed_by.all()[0]
  1258. self.assertEqual(expected_name, signer.name)
  1259. self.assertEqual(expected_email, signer.email)
  1260. # The created by field is also set, but to the sender of the
  1261. # email
  1262. self.assertEqual(sender_name, news.created_by)
  1263. def test_create_email_news_unknown_encoding_utf8(self):
  1264. """
  1265. Tests that creating an email news item from a message which does not
  1266. specify an encoding works correctly when the actual encoding is utf-8.
  1267. """
  1268. message = email.message.Message()
  1269. message['Subject'] = 'Some subject'
  1270. content = 'è'
  1271. raw_content = content.encode('utf-8')
  1272. message.set_payload(raw_content, 'utf-8')
  1273. del message['Content-Type']
  1274. news = EmailNews.objects.create_email_news(
  1275. message=message,
  1276. package=self.package)
  1277. # The news is successfully created
  1278. self.assertEqual(1, EmailNews.objects.count())
  1279. news = EmailNews.objects.all()[0]
  1280. # The news can be converted back to a Message instance
  1281. msg_from_news = message_from_bytes(news.content)
  1282. # The payload is correct?
  1283. self.assertEqual(raw_content, msg_from_news.get_payload(decode=True))
  1284. # It can be converted correctly to an actual unicode object
  1285. self.assertEqual(
  1286. content,
  1287. get_decoded_message_payload(msg_from_news))
  1288. def test_create_email_news_unknown_encoding_latin1(self):
  1289. """
  1290. Tests that creating an email news item from a message which does not
  1291. specify an encoding works correctly when the actual encoding is
  1292. latin1.
  1293. """
  1294. message = email.message.Message()
  1295. message['Subject'] = 'Some subject'
  1296. content = 'è'
  1297. raw_content = content.encode('latin-1')
  1298. message.set_payload(raw_content, 'latin-1')
  1299. del message['Content-Type']
  1300. news = EmailNews.objects.create_email_news(
  1301. message=message,
  1302. package=self.package)
  1303. # The news is successfully created
  1304. self.assertEqual(1, EmailNews.objects.count())
  1305. news = EmailNews.objects.all()[0]
  1306. # The news can be converted back to a Message instance
  1307. msg_from_news = message_from_bytes(news.content)
  1308. # The payload is correct?
  1309. self.assertEqual(raw_content, msg_from_news.get_payload(decode=True))
  1310. # It can be converted correctly to an actual unicode object
  1311. self.assertEqual(
  1312. content,
  1313. get_decoded_message_payload(msg_from_news, 'latin-1'))
  1314. def test_email_news_render(self):
  1315. """
  1316. Tests that an email news is correctly rendered when the encoding of the
  1317. message is unknown.
  1318. """
  1319. message = email.message.Message()
  1320. message['Subject'] = 'Some subject'
  1321. content = 'è'
  1322. # Create two news items: one latin-1 the other utf-8 encoded.
  1323. message.set_payload(content.encode('latin-1'), 'latin-1')
  1324. del message['Content-Type']
  1325. news_latin = EmailNews.objects.create_email_news(
  1326. message=message,
  1327. package=self.package)
  1328. message.set_payload(content.encode('utf-8'), 'utf-8')
  1329. del message['Content-Type']
  1330. news_utf = EmailNews.objects.create_email_news(
  1331. message=message,
  1332. package=self.package)
  1333. # Check that the latin-1 encoded news is correctly displayed
  1334. response = self.client.get(reverse('dtracker-news-page', kwargs={
  1335. 'news_id': news_latin.id,
  1336. }))
  1337. # The response contains the correctly decoded content
  1338. self.assertIn(content, response.content.decode('utf-8'))
  1339. # Check that the utf-8 encoded news is correctly displayed
  1340. response = self.client.get(reverse('dtracker-news-page', kwargs={
  1341. 'news_id': news_utf.id,
  1342. }))
  1343. # The response contains the correctly decoded content
  1344. self.assertIn(content, response.content.decode('utf-8'))
  1345. def create_email_news_with_links(self):
  1346. """Create email news with content that should be linkified."""
  1347. message = email.message.Message()
  1348. message['Subject'] = 'Some subject'
  1349. content = """fix "a > 5" for more
  1350. information https://www.debian.org/ thanks"""
  1351. message.set_payload(content)
  1352. return(EmailNews.objects.create_email_news(message=message,
  1353. package=self.package))
  1354. def test_email_news_render_links(self):
  1355. """
  1356. Tests that an email news is correctly rendered with html link when
  1357. needed and that quotes and angle brackets are properly escaped.
  1358. """
  1359. mail_news = self.create_email_news_with_links()
  1360. response = self.client.get(reverse('dtracker-news-page', kwargs={
  1361. 'news_id': mail_news.id,
  1362. }))
  1363. content = response.content.decode('utf-8')
  1364. self.assertInHTML(
  1365. '<a href="https://www.debian.org/">https://www.debian.org/</a>',
  1366. content)
  1367. # Ensure angle brackets and quotes are encoded
  1368. self.assertNotIn('"a > 5"', content)
  1369. self.assertIn('&quot;a &gt; 5&quot;', content)
  1370. def test_email_news_render_links_in_rss_feed(self):
  1371. """
  1372. Tests that an email news is correctly rendered within the package
  1373. RSS feed. HTML links are escaped once and normal quotes/angle brackets
  1374. are doubly escaped.
  1375. """
  1376. self.create_email_news_with_links()
  1377. response = self.client.get(
  1378. reverse('dtracker-package-rss-news-feed',
  1379. kwargs={'package_name': self.package}))
  1380. content_response = response.content.decode('utf-8')
  1381. self.assertIn(
  1382. '&lt;a href="https://www.debian.org/"&gt;'
  1383. 'https://www.debian.org/&lt;/a&gt;',
  1384. content_response)
  1385. self.assertIn('&amp;quot;a &amp;gt; 5&amp;quot;', content_response)
  1386. def test_email_news_render_latin1_message_without_encoding(self):
  1387. file_path = self.get_test_data_path('message-without-encoding')
  1388. with open(file_path, 'rb') as f:
  1389. content = f.read()
  1390. news = EmailNews.objects.create_email_news(
  1391. message=message_from_bytes(content),
  1392. package=self.package)
  1393. renderer = EmailNewsRenderer(news)
  1394. # Ensure the headers are correctly decoded
  1395. header_from = renderer.context['headers']['From']
  1396. self.assertEqual(header_from['emails'][0]['name'],
  1397. 'David Martínez Moreno')
  1398. self.assertEqual(header_from['emails'][0]['email'], 'ender@debian.org')
  1399. # Ensure the body is also correctly decoded as latin1
  1400. self.assertIn('Maintainer: David Martínez Moreno',
  1401. renderer.context['parts'][0])
  1402. class ActionItemTests(TestCase):
  1403. """
  1404. Tests for the :class:`distro_tracker.core.models.ActionItem` model.
  1405. """
  1406. def setUp(self):
  1407. self.package = PackageName.objects.create(name='dummy-package')
  1408. self.action_type = ActionItemType.objects.create(type_name='test-type')
  1409. self.add_test_template_dir()
  1410. def set_action_type_template(self, template_name):
  1411. """
  1412. Sets the template name for the test action item type.
  1413. """
  1414. self.action_type.full_description_template = template_name
  1415. self.action_type.save()
  1416. def test_full_description_from_template(self):
  1417. """
  1418. Tests that the
  1419. :attr:`distro_tracker.core.models.ActionItem.full_description` property
  1420. returns content by rendering the correct template.
  1421. """
  1422. self.set_action_type_template('action-item-test.html')
  1423. action_item = ActionItem.objects.create(
  1424. package=self.package,
  1425. item_type=self.action_type,
  1426. short_description='Short description of item')
  1427. self.assertIn(
  1428. "Item's PK is {pk}".format(pk=action_item.pk),
  1429. action_item.full_description)
  1430. self.assertIn(
  1431. "Short description: Short description of item",
  1432. action_item.full_description)
  1433. def test_full_description_unexisting_template(self):
  1434. """
  1435. Tests that the
  1436. :attr:`distro_tracker.core.models.ActionItem.full_description` returns
  1437. an empty full description if the given template does not exist.
  1438. """
  1439. self.set_action_type_template('this-template-does-not-exist.html')
  1440. action_item = ActionItem.objects.create(
  1441. package=self.package,
  1442. item_type=self.action_type,
  1443. short_description='Short description of item')
  1444. self.assertEqual('', action_item.full_description)
  1445. def test_full_description_no_template_given(self):
  1446. """
  1447. Tests that the
  1448. :attr:`distro_tracker.core.models.ActionItem.full_description` returns
  1449. an empty full description if no template is set for the item.
  1450. """
  1451. action_item = ActionItem.objects.create(
  1452. package=self.package,
  1453. item_type=self.action_type,
  1454. short_description='Short description of item')
  1455. self.assertEqual('', action_item.full_description)
  1456. def test_full_description_extra_data(self):
  1457. """
  1458. Tests that the
  1459. :attr:`distro_tracker.core.models.ActionItem.full_description` returns a
  1460. description which can use the extra_data of a
  1461. :class:`distro_tracker.core.models.ActionItem`.
  1462. """
  1463. self.set_action_type_template('action-item-test.html')
  1464. action_item = ActionItem.objects.create(
  1465. package=self.package,
  1466. item_type=self.action_type,
  1467. short_description='Short description of item')
  1468. action_item.extra_data = ['data1', 'data2']
  1469. action_item.save()
  1470. self.assertIn("data1, data2", action_item.full_description)
  1471. class TeamTests(TestCase):
  1472. """
  1473. Tests for the :class:`Team <distro_tracker.core.models.Team>` model.
  1474. """
  1475. def setUp(self):
  1476. self.password = 'asdf'
  1477. self.user = User.objects.create_user(
  1478. main_email='user@domain.com', password=self.password,
  1479. first_name='', last_name='')
  1480. self.team = Team.objects.create_with_slug(
  1481. owner=self.user, name="Team name")
  1482. self.package_name = PackageName.objects.create(name='dummy')
  1483. self.team.packages.add(self.package_name)
  1484. self.user_email = UserEmail.objects.create(
  1485. email='other@domain.com')
  1486. self.email_settings = \
  1487. EmailSettings.objects.create(user_email=self.user_email)
  1488. def assert_keyword_sets_equal(self, set1, set2):
  1489. self.assertEqual(
  1490. [k.name for k in set1],
  1491. [k.name for k in set2])
  1492. def assert_keyword_sets_not_equal(self, set1, set2):
  1493. self.assertNotEqual(
  1494. [k.name for k in set1],
  1495. [k.name for k in set2])
  1496. def test_no_membership_keywords(self):
  1497. """
  1498. Tests that when there are no membership keywords, the user's default
  1499. keywords are returned.
  1500. """
  1501. membership = self.team.add_members([self.user_email])[0]
  1502. MembershipPackageSpecifics.objects.create(
  1503. membership=membership,
  1504. package_name=self.package_name)
  1505. self.assert_keyword_sets_equal(
  1506. self.email_settings.default_keywords.all(),
  1507. membership.get_keywords(self.package_name))
  1508. def test_set_membership_keywords(self):
  1509. membership = self.team.add_members([self.user_email])[0]
  1510. keywords = Keyword.objects.all()[:3]
  1511. membership.set_membership_keywords([k.name for k in keywords])
  1512. # The set of membership keywords is correctly set
  1513. self.assert_keyword_sets_equal(
  1514. keywords, membership.default_keywords.all())
  1515. # A flag is set indicating that the set exists
  1516. self.assertTrue(membership.has_membership_keywords)
  1517. # The keywords returned for the package are equal to the membership
  1518. # keywords.
  1519. self.assert_keyword_sets_equal(
  1520. keywords,
  1521. membership.get_keywords(self.package_name))
  1522. def test_set_membership_package_specifics(self):
  1523. # Add another package to the team
  1524. package = self.team.packages.create(name='other-pkg')
  1525. self.team.packages.add(package)
  1526. membership = self.team.add_members([self.user_email])[0]
  1527. keywords = Keyword.objects.all()[:3]
  1528. membership.set_keywords(self.package_name, [k.name for k in keywords])
  1529. # A MembershipPackageSpecifics instance is created
  1530. self.assertEqual(1, MembershipPackageSpecifics.objects.count())
  1531. # The keywords returned for the package are correct
  1532. self.assert_keyword_sets_equal(
  1533. keywords,
  1534. membership.get_keywords(self.package_name))
  1535. # But the other package still returns the user's default keywords
  1536. self.assert_keyword_sets_equal(
  1537. self.email_settings.default_keywords.all(),
  1538. membership.get_keywords(package))
  1539. def test_mute_package(self):
  1540. """
  1541. Tests that it is possible to mute only one package in the team.
  1542. """
  1543. package = self.team.packages.create(name='other-pkg')
  1544. self.team.packages.add(package)
  1545. membership = self.team.add_members([self.user_email])[0]
  1546. membership.mute_package(self.package_name)
  1547. # Refresh the instance
  1548. membership = TeamMembership.objects.get(pk=membership.pk)
  1549. # The whole membership is not muted
  1550. self.assertFalse(membership.muted)
  1551. # The package is though
  1552. self.assertTrue(membership.is_muted(self.package_name))
  1553. # The other package isn't
  1554. self.assertFalse(membership.is_muted(package))
  1555. class SourcePackageNameTests(TestCase):
  1556. """
  1557. Tests for the :class:`distro_tracker.core.models.SourcePackageName` model.
  1558. """
  1559. def setUp(self):
  1560. self.package = SourcePackageName.objects.create(name='dummy-package')
  1561. self.binary_package = BinaryPackageName.objects.create(
  1562. name='binary-package')
  1563. self.pseudo_package = \
  1564. PseudoPackageName.objects.create(name='pseudo-pkg')
  1565. self.src_pkg = SourcePackage.objects.create(
  1566. source_package_name=self.package, version='1.0.0')
  1567. self.bin_pkg = BinaryPackage.objects.create(
  1568. binary_package_name=self.binary_package,
  1569. source_package=self.src_pkg,
  1570. short_description='a useful package')
  1571. self.src_pkg.binary_packages = [self.binary_package]
  1572. self.src_pkg.save()
  1573. self.bin_pkg.save()
  1574. def test_get_short_description_with_single_binary(self):
  1575. self.assertEqual(self.package.short_description(), 'a useful package')
  1576. def test_get_short_description_with_multiple_binary(self):
  1577. """
  1578. When we have multiple binary packages, we want to pick the
  1579. package that has the same name as the source package.
  1580. """
  1581. binary_package, _ = BinaryPackageName.objects.get_or_create(
  1582. name='dummy-package')
  1583. BinaryPackage.objects.get_or_create(
  1584. binary_package_name=binary_package,
  1585. source_package=self.src_pkg,
  1586. short_description='another useful package')
  1587. self.src_pkg.binary_packages = [self.binary_package, binary_package]
  1588. self.src_pkg.save()
  1589. self.assertEqual(self.package.short_description(),
  1590. 'another useful package')
  1591. def test_get_short_description_with_no_source(self):
  1592. pkg = SourcePackageName.objects.create(name='some-package')
  1593. self.assertEqual(pkg.short_description(), '')
  1594. def test_get_short_description_with_source_and_no_binary(self):
  1595. pkg = SourcePackageName.objects.create(name='some-package')
  1596. SourcePackage.objects.create(source_package_name=pkg, version='1.0.0')
  1597. self.assertEqual(pkg.short_description(), '')