def test_updateStatus_BUILDING_sets_date_started(self): # updateStatus sets date_started on transition to BUILDING. # date_first_dispatched is also set if it isn't already. self.assertEqual(BuildStatus.NEEDSBUILD, self.build_farm_job.status) self.assertIs(None, self.build_farm_job.date_started) self.assertIs(None, self.build_farm_job.date_first_dispatched) self.build_farm_job.updateStatus(BuildStatus.CANCELLED) self.assertIs(None, self.build_farm_job.date_started) self.assertIs(None, self.build_farm_job.date_first_dispatched) # Setting it to BUILDING for the first time sets date_started # and date_first_dispatched. self.build_farm_job.updateStatus(BuildStatus.BUILDING) self.assertIsNot(None, self.build_farm_job.date_started) first = self.build_farm_job.date_started self.assertEqual(first, self.build_farm_job.date_first_dispatched) self.build_farm_job.updateStatus(BuildStatus.FAILEDTOBUILD) with admin_logged_in(): self.build_farm_job.retry() self.assertIs(None, self.build_farm_job.date_started) self.assertEqual(first, self.build_farm_job.date_first_dispatched) # But BUILDING a second time doesn't change # date_first_dispatched. self.build_farm_job.updateStatus(BuildStatus.BUILDING) self.assertThat(self.build_farm_job.date_started, GreaterThan(first)) self.assertEqual(first, self.build_farm_job.date_first_dispatched)
def test_findPerson(self): # The search can be restricted to people. with admin_logged_in(): person_name = self.factory.makePerson().name self.factory.makeTeam(name='%s-team' % person_name) self.assertReturnsPeople( [person_name], '/people?ws.op=findPerson&text=%s' % person_name)
def test_bugtracker_with_private_project(self): tracker = self.factory.makeBugTracker() product = self.factory.makeProduct( information_type=InformationType.PROPRIETARY, name='foobar') with admin_logged_in(): product.bugtracker = tracker view = create_initialized_view(tracker, name='+index') self.assertEqual([], view.related_projects)
def test_default_bugtask(self): product = self.factory.makeProduct() bug = self.factory.makeBug(target=product) first_task = bug.default_bugtask other_task = self.factory.makeBugTask( bug=bug, target=self.factory.makeProduct()) self.assertEqual(first_task, bug.default_bugtask) # default_bugtask avoids an inactive product if possible. with admin_logged_in(): first_task.target.active = False self.assertEqual(other_task, bug.default_bugtask) # But it'll use the first inactive one if it has to. with admin_logged_in(): other_task.target.active = False self.assertEqual(first_task, bug.default_bugtask) # An active distro task wins over an inactive product. distro_task = self.factory.makeBugTask( bug=bug, target=self.factory.makeDistribution()) self.assertEqual(distro_task, bug.default_bugtask)
def test_ppas_link(self): view = create_initialized_view(self.distro, "+index") ppas_link = soupmatchers.HTMLContains( soupmatchers.Tag("PPAs link", "a", text="Personal Package Archives")) self.assertThat(view(), Not(ppas_link)) with admin_logged_in(): self.distro.supports_ppas = True self.assertThat(view(), ppas_link)
def test_tracker_with_private_project(self): tracker = self.factory.makeBugTracker() product = self.factory.makeProduct( information_type=InformationType.PROPRIETARY, name='foobar') with admin_logged_in(): product.bugtracker = tracker url = canonical_url(getUtility(IBugTrackerSet)) browser = self.getUserBrowser(url) self.assertIn(tracker.name, browser.contents) self.assertNotIn('foobar', browser.contents)
def test_related_projects(self): # Related products and projectgroups are shown by the view. tracker = self.factory.makeBugTracker() project_group = self.factory.makeProject() product = self.factory.makeProduct() with admin_logged_in(): project_group.bugtracker = tracker product.bugtracker = tracker view = create_initialized_view(tracker, name='+index') self.assertEqual([project_group, product], view.related_projects)
def create_mp(): with admin_logged_in(): branch = self.factory.makeBranch( target=project, stacked_on=self.factory.makeBranch( target=project, information_type=InformationType.PRIVATESECURITY), information_type=InformationType.PRIVATESECURITY) self.factory.makeBranchMergeProposal(source_branch=source, target_branch=branch)
def test_delete_is_restricted(self): with admin_logged_in(): ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA) ppa_url = api_url(ppa) ws = webservice_for_person( self.factory.makePerson(), permission=OAuthPermission.WRITE_PRIVATE) # A random user can't delete someone else's PPA. self.assertEqual(401, ws.delete(ppa_url, api_version='devel').status)
def test_linked_projects_only_shows_active_projects(self): # Inactive projects are not shown as the related projects. tracker = self.factory.makeBugTracker() active_product = self.factory.makeProduct() inactive_product = self.factory.makeProduct() with admin_logged_in(): active_product.bugtracker = tracker inactive_product.bugtracker = tracker inactive_product.active = False view = create_initialized_view(tracker, name='+index') self.assertEqual([active_product], view.related_projects)
def test_eta(self): # BuildView.eta returns a non-None value when it should, or None # when there's no start time. build = self.factory.makeBinaryPackageBuild() build.queueBuild() self.factory.makeBuilder(processor=build.processor, virtualized=True) self.assertIsNot(None, create_initialized_view(build, '+index').eta) with admin_logged_in(): build.archive.disable() flush_database_caches() self.assertIs(None, create_initialized_view(build, '+index').eta)
def setUpStoreUpload(self): self.pushConfig( "snappy", store_url="http://sca.example/", store_upload_url="http://updown.example/") with admin_logged_in(): snappyseries = self.factory.makeSnappySeries( usable_distro_series=[self.build.snap.distro_series]) with person_logged_in(self.requester): self.build.snap.store_series = snappyseries self.build.snap.store_name = self.factory.getUniqueUnicode() self.build.snap.store_secrets = {"root": Macaroon().serialize()}
def test_destroySelf_clears_release(self): # Destroying a sourcepackagerecipebuild removes references to it from # its releases. build = self.factory.makeSourcePackageRecipeBuild() release = self.factory.makeSourcePackageRelease( source_package_recipe_build=build) self.assertEqual(build, release.source_package_recipe_build) with admin_logged_in(): build.destroySelf() self.assertIs(None, release.source_package_recipe_build) transaction.commit()
def test_rescore_build_wrong_state(self): """If the build isn't queued, you can't rescore it.""" build = self.makeRecipeBuild() with admin_logged_in(): build.cancel() transaction.commit() build_url = canonical_url(build) logout() browser = self.getUserBrowser(build_url, user=self.admin) self.assertRaises(LinkNotFoundError, browser.getLink, 'Rescore build')
def test_getByEmail(self): # You can get a person by their email address. with admin_logged_in(): person = self.factory.makePerson() person_name = person.name person_email = person.preferredemail.email self.assertEqual( person_name, self.webservice.get( '/people?ws.op=getByEmail&email=%s' % person_email ).jsonBody()['name'])
def test_deleteSSHKeyFromSSO_rejects_bad_key_type(self, dry_run=False): with admin_logged_in(): person = self.factory.makePerson() openid_id = person.account.openid_identifiers.any().identifier response = self.deleteSSHKeyFromSSO( openid_id, 'foo keydata comment', dry_run) self.assertEqual(400, response.status) self.assertEqual( "Invalid SSH key type: 'foo'", response.body)
def test_deleteSSHKeyFromSSO_is_restricted(self, dry_run=False): with admin_logged_in(): target = self.factory.makePerson() openid_id = target.account.openid_identifiers.any().identifier webservice = webservice_for_person( target, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.named_post( '/people', 'deleteSSHKeyFromSSO', openid_identifier=openid_id, key_text='ssh-rsa foo bar', dry_run=dry_run, api_version='devel') self.assertEqual(401, response.status)
def test_rendering(self): default_repo = self.factory.makeGitRepository( owner=self.owner, target=self.target, name="foo") self.factory.makeGitRefs( default_repo, paths=["refs/heads/master", "refs/heads/bug-1234"]) other_repo = self.factory.makeGitRepository( owner=self.owner, target=self.target, name="bar") self.factory.makeGitRefs(other_repo, paths=["refs/heads/bug-2468"]) with admin_logged_in(): getUtility(IGitRepositorySet).setDefaultRepositoryForOwner( owner=self.owner, target=self.target, repository=default_repo, user=self.owner) view = create_initialized_view(self.owner_target, '+git') self.assertEqual(default_repo, view.default_git_repository) content = view() soup = BeautifulSoup(content) # Clone instructions for the default repo are present. self.assertEqual( 'https://git.launchpad.dev/~dev/%s' % self.target_path, soup.find(attrs={'class': 'https-url'}).find(text=True)) self.assertEqual( 'https://git.launchpad.dev/~dev/%s' % self.target_path, soup.find(text='Browse the code').parent['href']) # The default repo's branches are shown. table = soup.find( 'div', id='default-repository-branches').find('table') self.assertContentEqual( ['master', 'bug-1234'], [link.find(text=True) for link in table.findAll('a')]) self.assertEndsWith( table.find(text="bug-1234").parent['href'], "/~dev/%s/+git/foo/+ref/bug-1234" % self.target_path) # Other repos are listed. table = soup.find( 'div', id='gitrepositories-table-listing').find('table') self.assertContentEqual( ['lp:~dev/%s' % self.target_path, 'lp:~dev/%s/+git/bar' % self.target_path], [link.find(text=True) for link in table.findAll('a')]) self.assertEndsWith( table.find( text="lp:~dev/%s/+git/bar" % self.target_path).parent['href'], "/~dev/%s/+git/bar" % self.target_path) # But not their branches. self.assertNotIn('bug-2468', content)
def test_index_compressors(self): distroseries = self.factory.makeDistroSeries() self.assertEqual( [IndexCompressionType.GZIP, IndexCompressionType.BZIP2], distroseries.index_compressors) with admin_logged_in(): distroseries.index_compressors = [IndexCompressionType.XZ] self.assertEqual([IndexCompressionType.XZ], distroseries.index_compressors) naked_distroseries = removeSecurityProxy(distroseries) self.assertEqual( ["xz"], naked_distroseries.publishing_options["index_compressors"])
def test_destroySelf_destroys_referenced(self): # Destroying a sourcepackagerecipebuild also destroys the # PackageBuild and BuildFarmJob it references. build = self.factory.makeSourcePackageRecipeBuild() store = Store.of(build) naked_build = removeSecurityProxy(build) # Ensure database ids are set. store.flush() build_farm_job_id = naked_build.build_farm_job_id with admin_logged_in(): build.destroySelf() self.assertIs(None, store.get(BuildFarmJob, build_farm_job_id))
def test_cancel_build_wrong_state(self): """If the build isn't queued, you can't cancel it.""" build = self.makeRecipeBuild() with admin_logged_in(): build.cancel() transaction.commit() build_url = canonical_url(build) owner = build.archive.owner logout() browser = self.getUserBrowser(build_url, user=owner) self.assertRaises(LinkNotFoundError, browser.getLink, 'Cancel build')
def test_deleteSSHKeyFromSSO_allows_newlines_dry_run(self): with admin_logged_in(): person = removeSecurityProxy(self.factory.makePerson()) kind, data, comment = self.factory.makeSSHKeyText().split(" ", 2) key_text = "%s %s %s\n" % (kind, textwrap.fill(data), comment) key = getUtility(ISSHKeySet).new(person, key_text, check_key=False) openid_id = person.account.openid_identifiers.any().identifier response = self.deleteSSHKeyFromSSO( openid_id, key.getFullKeyText(), dry_run=True) self.assertEqual(200, response.status) self.assertEqual(1, person.sshkeys.count())
def test_delete(self): with admin_logged_in(): faq = self.factory.makeFAQ() faq_url = api_url(faq) expert = self.factory.makePerson( member_of=[getUtility(IPersonSet).getByName('registry')]) webservice = webservice_for_person( expert, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.delete(faq_url, api_version='devel') self.assertEqual(200, response.status) response = webservice.get(faq_url, api_version='devel') self.assertEqual(404, response.status)
def test_addSSHKeyFromSSO_works(self): with admin_logged_in(): person = removeSecurityProxy(self.factory.makePerson()) openid_id = person.account.openid_identifiers.any().identifier full_key = self.factory.makeSSHKeyText() _, keytext, comment = full_key.split(' ', 2) response = self.addSSHKeyForPerson(openid_id, full_key) self.assertEqual(200, response.status) [key] = person.sshkeys self.assertEqual(SSHKeyType.RSA, key.keytype) self.assertEqual(keytext, key.keytext) self.assertEqual(comment, key.comment)
def test_getOrCreateSoftwareCenterCustomer_rejects_suspended(self): # Suspended accounts are not returned. with admin_logged_in(): existing = self.factory.makePerson( email='*****@*****.**', account_status=AccountStatus.SUSPENDED) oid = OpenIdIdentifier() oid.account = existing.account oid.identifier = u'somebody' Store.of(existing).add(oid) sca = getUtility(IPersonSet).getByName('software-center-agent') response = self.getOrCreateSoftwareCenterCustomer(sca) self.assertEqual(400, response.status)
def test_getByName(self): # lp.snappy_serieses.getByName returns a matching SnappySeries. person = self.factory.makePerson() webservice = webservice_for_person( person, permission=OAuthPermission.READ_PUBLIC) webservice.default_api_version = "devel" with admin_logged_in(): self.factory.makeSnappySeries(name="dummy") response = webservice.named_get("/+snappy-series", "getByName", name="dummy") self.assertEqual(200, response.status) self.assertEqual("dummy", response.jsonBody()["name"])
def test_query_count_git(self): if not self.supports_git: self.skipTest("Context doesn't support Git repositories.") with admin_logged_in(): for i in range(7): self.makeGitMergeProposal() flush_database_caches() with StormStatementRecorder() as recorder: self.getViewBrowser(self.context, self.view_name, rootsite='code', user=self.user) self.assertThat(recorder, HasQueryCount(LessThan(47)))
def test_can_retrieve_keys_for_multiple_people(self): with admin_logged_in(): person1 = self.factory.makePerson() person1_key1 = self.factory.makeSSHKey(person1) person1_key2 = self.factory.makeSSHKey(person1) person2 = self.factory.makePerson() person2_key1 = self.factory.makeSSHKey(person2) keyset = getUtility(ISSHKeySet) keys = keyset.getByPeople([person1, person2]) self.assertEqual(3, keys.count()) self.assertContentEqual([person1_key1, person1_key2, person2_key1], keys)
def test_getByOpenIDIdentifier(self): # You can get a person by their OpenID identifier URL. with admin_logged_in(): person = self.factory.makePerson() person_name = person.name person_openid = person.account.openid_identifiers.one().identifier self.assertEqual( person_name, self.webservice.get( '/people?ws.op=getByOpenIDIdentifier&' 'identifier=http://openid.launchpad.dev/%%2Bid/%s' % person_openid, api_version='devel').jsonBody()['name'])
def test_reviewer_can_edit_git_merge_proposal(self): person = self.factory.makePerson() product = self.factory.makeProduct() [target] = self.factory.makeGitRefs(target=product) [source] = self.factory.makeGitRefs(target=product) mp = self.factory.makeBranchMergeProposalForGit(source_ref=source, target_ref=target) with person_logged_in(person): self.assertFalse(check_permission('launchpad.Edit', mp)) with admin_logged_in(): target.repository.reviewer = person with person_logged_in(person): self.assertTrue(check_permission('launchpad.Edit', mp))
def test_deleteSSHKeyFromSSO_allows_newlines(self): # Adding these should normally be forbidden, but we want users to be # able to delete existing rows. with admin_logged_in(): person = removeSecurityProxy(self.factory.makePerson()) kind, data, comment = self.factory.makeSSHKeyText().split(" ", 2) key_text = "%s %s %s\n" % (kind, textwrap.fill(data), comment) key = getUtility(ISSHKeySet).new(person, key_text, check_key=False) openid_id = person.account.openid_identifiers.any().identifier response = self.deleteSSHKeyFromSSO( openid_id, key.getFullKeyText()) self.assertEqual(200, response.status) self.assertEqual(0, person.sshkeys.count())
def test_proprietary_branch_for_series_user_has_artifact_grant(self): # A user can be the owner of a branch which is the series # branch of a proprietary product, and the user may only have # an access grant for the branch but no policy grant for the # product. In this case, the branch owner does get any information #about the series. product_owner = self.factory.makePerson() product = self.factory.makeProduct( owner=product_owner, information_type=InformationType.PROPRIETARY) branch_owner = self.factory.makePerson() sharing_service = getUtility(IService, 'sharing') with person_logged_in(product_owner): # The branch owner needs to have a policy grant at first # so that they can create the branch. sharing_service.sharePillarInformation( product, branch_owner, product_owner, {InformationType.PROPRIETARY: SharingPermission.ALL}) proprietary_branch = self.factory.makeProductBranch( product, owner=branch_owner, name='special-branch', information_type=InformationType.PROPRIETARY) series = self.factory.makeProductSeries( product=product, branch=proprietary_branch) sharing_service.deletePillarGrantee( product, branch_owner, product_owner) # Admin help is needed: Product owners do not have the # permission to create artifact grants for branches they # do not own, and the branch owner does have the permission # to issue grants related to the product. with admin_logged_in(): sharing_service.ensureAccessGrants( [branch_owner], product_owner, branches=[proprietary_branch]) with person_logged_in(branch_owner): view = create_initialized_view( branch_owner, name="+branches", rootsite='code', principal=branch_owner) self.assertIn(proprietary_branch, view.branches().batch) # The product series related to the branch is not returned # for the branch owner. self.assertEqual( [], view.branches().getProductSeries(proprietary_branch)) with person_logged_in(product_owner): # The product series related to the branch is returned # for the product owner. view = create_initialized_view( branch_owner, name="+branches", rootsite='code', principal=branch_owner) self.assertEqual( [series], view.branches().getProductSeries(proprietary_branch))
def test_collection(self): # lp.snappy_serieses is a collection of all SnappySeries. person = self.factory.makePerson() webservice = webservice_for_person( person, permission=OAuthPermission.READ_PUBLIC) webservice.default_api_version = "devel" with admin_logged_in(): for i in range(3): self.factory.makeSnappySeries(name="ss-%d" % i) response = webservice.get("/+snappy-series") self.assertEqual(200, response.status) self.assertContentEqual( ["ss-0", "ss-1", "ss-2", "15.04-core", "16"], [entry["name"] for entry in response.jsonBody()["entries"]])
def test_private_master_not_linked_without_permission(self): bug = self.factory.makeBug( information_type=InformationType.PRIVATESECURITY) dupe = self.factory.makeBug() with admin_logged_in(): dupe.markAsDuplicate(bug) with person_logged_in(dupe.owner): getUtility(IOpenLaunchBag).add(dupe.default_bugtask) html = create_initialized_view(dupe.default_bugtask, "+index", principal=dupe.owner)() dupe_warning = find_tag_by_id(html, 'warning-comment-on-duplicate') # There is no link in the dupe_warning. self.assertTrue('href' not in dupe_warning)
def test_builder_index_private(self): archive = self.factory.makeArchive(private=True) with admin_logged_in(): build = self.makeBuildingRecipe(archive=archive) url = canonical_url(removeSecurityProxy(build).builder) random_person = self.factory.makePerson() logout() # An unrelated user can't see the logtail of a private build. browser = self.makeNonRedirectingBrowser(url, random_person) self.assertNotIn('i am failing', browser.contents) # But someone who can see the archive can. browser = self.makeNonRedirectingBrowser(url, archive.owner) self.assertIn('i am failing', browser.contents)
def test_page_is_batched(self): self.factory.makeBugTracker() self.factory.makeBugTracker() inactive_tracker1 = self.factory.makeBugTracker() inactive_tracker2 = self.factory.makeBugTracker() with admin_logged_in(): inactive_tracker1.active = False inactive_tracker2.active = False trackers = getUtility(IBugTrackerSet) url = (canonical_url(trackers) + "/+index?active_batch=1&inactive_batch=1") browser = self.getUserBrowser(url) content = browser.contents # XXX RobertCollns 20100919 bug=642504. The support for multiple batches # isn't complete and the id for the nav links gets duplicated. #self.assertEqual('next', # find_tag_by_id(content, 'upper-batch-nav-batchnav-next')['class']) #self.assertEqual('next', # find_tag_by_id(content, 'lower-batch-nav-batchnav-next')['class']) # Instead we check the string appears. self.assertTrue('upper-batch-nav-batchnav-next' in content)
def test_admin_modify_packageset(self): # Admins can modify packagesets with admin_logged_in(): self.modifyPackageset()
def test_find(self): # It's possible to find people by name. with admin_logged_in(): person_name = self.factory.makePerson().name self.assertReturnsPeople( [person_name], '/people?ws.op=find&text=%s' % person_name)
def test_create_packagset_as_admin(self): # Admins can create packagesets with admin_logged_in(): self.ps_set.new(self.factory.getUniqueUnicode(), self.factory.getUniqueUnicode(), self.factory.makePerson())