def test_default_collection(self): # Make it easy to filter out sample data store = IStore(Processor) store.execute("UPDATE Processor SET name = 'sample_data_' || name") self.factory.makeProcessor(name='q1') self.factory.makeProcessor(name='i686') self.factory.makeProcessor(name='g4') logout() collection = self.webservice.get( '/+processors?ws.size=10', api_version='devel').jsonBody() self.assertEquals( ['g4', 'i686', 'q1'], sorted( processor['name'] for processor in collection['entries'] if not processor['name'].startswith('sample_data_')))
def _set_collection(self, cls, enum, attribute, current_set, desired_set): desired_set = frozenset(desired_set) if desired_set == frozenset(enum.items): # Setting all is the same as setting none, and setting none is # cheaper for reading and storage. desired_set = frozenset() # Add missing. store = IStore(cls) for kind in desired_set.difference(current_set): bsf = cls() bsf.filter = self setattr(bsf, attribute, kind) store.add(bsf) # Remove unused. kind = getattr(cls, attribute) store.find(cls, cls.filter == self, kind.is_in(current_set.difference(desired_set))).remove()
def current_published(self): """See IDistroArchSeriesBinaryPackage.""" current = IStore(BinaryPackagePublishingHistory).find( BinaryPackagePublishingHistory, BinaryPackagePublishingHistory.status == PackagePublishingStatus.PUBLISHED, *self._getPublicationJoins() ).order_by(Desc(BinaryPackagePublishingHistory.datecreated) ).first() if current is None: raise NotFoundError("Binary package %s not published in %s/%s" % (self.binarypackagename.name, self.distroarchseries.distroseries.name, self.distroarchseries.architecturetag)) return current
def create(cls, blob): """See `IProcessApportBlobJobSource`.""" # If there's already a job for the BLOB, don't create a new one. # We also include jobs which have been completed when checking # for exisiting jobs, since a BLOB should only be processed # once. job_for_blob = IStore(ApportJob).find( ApportJob, ApportJob.blob == blob, ApportJob.job_type == cls.class_job_type, ApportJob.job == Job.id, ).any() if job_for_blob is not None: return cls(job_for_blob) else: return super(ProcessApportBlobJob, cls).create(blob)
def releases(self): """See IDistroArchSeriesBinaryPackage.""" ret = IStore(BinaryPackageRelease).find( BinaryPackageRelease, *self._getPublicationJoins() ).order_by(Desc(BinaryPackageRelease.datecreated) ).config(distinct=True) result = [] versions = set() for bpr in ret: if bpr.version not in versions: versions.add(bpr.version) darbpr = DistroArchSeriesBinaryPackageRelease( distroarchseries=self.distroarchseries, binarypackagerelease=bpr) result.append(darbpr) return result
def __init__(self, *args, **kwargs): """Construct a collection, possibly based on another one. :param base: Optional collection that this collection is based on. The new collection will inherit its configuration. :param conditions: Optional Storm select conditions, e.g. `MyClass.attribute > 2`. :param classes: A class, or tuple or list of classes, that should go into the "FROM" clause of the new collection. This need not include classes that are already in the base collection, or that are included as outer joins. :param store: Optional: Storm `Store` to use. """ starting_tables = [] if len(args) >= 1 and isinstance(args[0], Collection): # There's a base collection. base = args[0] conditions = args[1:] else: # We're starting a fresh collection. base = None conditions = args if self.starting_table is not None: starting_tables = [self.starting_table] self.base = base if base is None: base_conditions = (True, ) base_tables = [] else: self.store = base.store base_conditions = base.conditions base_tables = list(base.tables) self.store = kwargs.get('store') if self.store is None: from lp.services.librarian.model import LibraryFileAlias self.store = IStore(LibraryFileAlias) self.tables = (starting_tables + base_tables + self._parseTablesArg(kwargs.get('tables', []))) self.conditions = base_conditions + conditions
def storeRemoteProductsAndComponents(self, bz_bugtracker, lp_bugtracker): """Stores parsed product/component data from bz_bugtracker""" components_to_add = [] for product in bz_bugtracker.products.itervalues(): # Look up the component group id from Launchpad for the product # if it already exists. Otherwise, add it. lp_component_group = lp_bugtracker.getRemoteComponentGroup( product['name']) if lp_component_group is None: lp_component_group = lp_bugtracker.addRemoteComponentGroup( product['name']) if lp_component_group is None: self.logger.warning("Failed to add new component group") continue else: for component in lp_component_group.components: if (component.name in product['components'] or component.is_visible == False or component.is_custom == True): # We already know something about this component, # or a user has configured it, so ignore it del product['components'][component.name] else: # Component is now missing from Bugzilla, # so drop it here too store = IStore(BugTrackerComponent) store.find( BugTrackerComponent, BugTrackerComponent.id == component.id, ).remove() # The remaining components in the collection will need to be # added to launchpad. Record them for now. for component in product['components'].values(): components_to_add.append( (component['name'], lp_component_group, True, False)) if len(components_to_add) > 0: self.logger.debug("...Inserting components into database") bulk.create( (BugTrackerComponent.name, BugTrackerComponent.component_group, BugTrackerComponent.is_visible, BugTrackerComponent.is_custom), components_to_add) transaction.commit() self.logger.debug("...Done")
def getBinaryFiles(self, distroseries, pocket): """Fetch publishing information about all published binary files. The publishing information consists of tuples with 'sourcename', 'filename', 'component' and 'architecture' strings, in this order. :param distroseries: target `IDistroSeries` :param pocket: target `PackagePublishingPocket` :return: a `ResultSet` with the binary files information tuples. """ columns = ( SourcePackageName.name, LibraryFileAlias.filename, Component.name, Concatenate(u"binary-", DistroArchSeries.architecturetag), ) join_conditions = [ BinaryPackageRelease.id == BinaryPackagePublishingHistory.binarypackagereleaseID, BinaryPackageFile.binarypackagereleaseID == BinaryPackagePublishingHistory.binarypackagereleaseID, BinaryPackageBuild.id == BinaryPackageRelease.buildID, SourcePackageName.id == BinaryPackageBuild.source_package_name_id, LibraryFileAlias.id == BinaryPackageFile.libraryfileID, DistroArchSeries.id == BinaryPackagePublishingHistory.distroarchseriesID, Component.id == BinaryPackagePublishingHistory.componentID, ] select_conditions = [ DistroArchSeries.distroseriesID == distroseries.id, BinaryPackagePublishingHistory.archive == self.publisher.archive, BinaryPackagePublishingHistory.pocket == pocket, BinaryPackagePublishingHistory.status == PackagePublishingStatus.PUBLISHED, ] if not self.publisher.archive.publish_debug_symbols: select_conditions.append(BinaryPackageRelease.binpackageformat != BinaryPackageFormat.DDEB) result_set = IStore(BinaryPackageRelease).find( columns, *(join_conditions + select_conditions)) return result_set.order_by(LibraryFileAlias.filename, BinaryPackageFile.id)
def _getSharedPillars(self, person, user, pillar_class, extra_filter=None): """Helper method for getSharedProjects and getSharedDistributions. pillar_class is either Product or Distribution. Products define the owner foreign key attribute as _owner so we need to account for that, but otherwise the logic is the same for both pillar types. """ if user is None: return [] store = IStore(AccessPolicyGrantFlat) roles = IPersonRoles(user) if roles.in_admin: filter = True else: with_statement = With("teams", Select(TeamParticipation.teamID, tables=TeamParticipation, where=TeamParticipation.person == user.id)) teams_sql = SQL("SELECT team from teams") store = store.with_(with_statement) if IProduct.implementedBy(pillar_class): ownerID = pillar_class._ownerID else: ownerID = pillar_class.ownerID filter = Or( extra_filter or False, ownerID.is_in(teams_sql), pillar_class.driverID.is_in(teams_sql)) tables = [ AccessPolicyGrantFlat, Join( AccessPolicy, AccessPolicyGrantFlat.policy_id == AccessPolicy.id)] if IProduct.implementedBy(pillar_class): access_policy_column = AccessPolicy.product_id else: access_policy_column = AccessPolicy.distribution_id result_set = store.find( pillar_class, pillar_class.id.is_in( Select( columns=access_policy_column, tables=tables, where=(AccessPolicyGrantFlat.grantee_id == person.id)) ), filter) return result_set
def _set_tags(self, tags): """Update the tags to filter on. The tags can be qualified with a leading hyphen, and can be bundled in any iterable. If they are passed within a `searchbuilder.any` or `searchbuilder.all` object, the `find_all_tags` attribute will be updated to match. Wildcard tags - `*` and `-*` - can be given too, and will update `include_any_tags` and `exclude_any_tags`. """ # Deal with searchbuilder terms. if isinstance(tags, searchbuilder.all): self.find_all_tags = True tags = frozenset(tags.query_values) elif isinstance(tags, searchbuilder.any): self.find_all_tags = False tags = frozenset(tags.query_values) else: # Leave find_all_tags unchanged. tags = frozenset(tags) wildcards = frozenset((u"*", u"-*")).intersection(tags) # Set wildcards. self.include_any_tags = "*" in wildcards self.exclude_any_tags = "-*" in wildcards # Deal with other tags. tags = tags - wildcards store = IStore(BugSubscriptionFilterTag) current_tag_filters = dict( (tag_filter.qualified_tag, tag_filter) for tag_filter in store.find( BugSubscriptionFilterTag, BugSubscriptionFilterTag.filter == self)) # Remove unused tags. for tag in set(current_tag_filters).difference(tags): tag_filter = current_tag_filters.pop(tag) store.remove(tag_filter) # Add additional tags. for tag in tags.difference(current_tag_filters): tag_filter = BugSubscriptionFilterTag() tag_filter.filter = self tag_filter.include = not tag.startswith("-") tag_filter.tag = tag.lstrip("-") store.add(tag_filter)
def getSubscriptionsForTeams(self, person, teams): """See `IMailingListSet`.""" store = IStore(MailingList) team_ids = set(map(operator.attrgetter("id"), teams)) lists = dict( store.find((MailingList.teamID, MailingList.id), MailingList.teamID.is_in(team_ids), MailingList.status.is_in(USABLE_STATUSES))) subscriptions = dict( store.find( (MailingListSubscription.mailing_listID, MailingListSubscription.id), MailingListSubscription.person == person, MailingListSubscription.mailing_listID.is_in(lists.values()))) by_team = {} for team, mailing_list in lists.items(): by_team[team] = (mailing_list, subscriptions.get(mailing_list)) return by_team
def checkPillarAccess(self, pillars, information_type, person): """See `ISharingService`.""" policies = getUtility(IAccessPolicySource).find([ (pillar, information_type) for pillar in pillars ]) policy_ids = [policy.id for policy in policies] if not policy_ids: return False store = IStore(AccessPolicyGrant) tables = [ AccessPolicyGrant, Join(TeamParticipation, TeamParticipation.teamID == AccessPolicyGrant.grantee_id), ] result = store.using(*tables).find( AccessPolicyGrant, AccessPolicyGrant.policy_id.is_in(policy_ids), TeamParticipation.personID == person.id) return not result.is_empty()
def iterReady(cls): """Iterate through all ready PackageCopyJobs. Even though it's slower, we repeat the query each time in order that very long queues of mass syncs can be pre-empted by other jobs. """ seen = set() while True: jobs = IStore(PackageCopyJob).find( PackageCopyJob, PackageCopyJob.job_type == cls.class_job_type, PackageCopyJob.job == Job.id, Job.id.is_in(Job.ready_jobs), Not(Job.id.is_in(seen))) jobs.order_by(PackageCopyJob.copy_policy) job = jobs.first() if job is None: break seen.add(job.job_id) yield cls(job)
def preloadForBuildFarmJobs(self, builds): """See `IBuildQueueSet`.""" from lp.buildmaster.model.builder import Builder bqs = list( IStore(BuildQueue).find( BuildQueue, BuildQueue._build_farm_job_id.is_in([ removeSecurityProxy(b).build_farm_job_id for b in builds ]))) load_related(Builder, bqs, ['builderID']) prefetched_data = dict( (removeSecurityProxy(buildqueue)._build_farm_job_id, buildqueue) for buildqueue in bqs) for build in builds: bq = prefetched_data.get( removeSecurityProxy(build).build_farm_job_id) get_property_cache(build).buildqueue_record = bq return bqs
def test_manifest(self): """Manifest should start empty, but accept SourcePackageRecipeData.""" recipe = self.factory.makeSourcePackageRecipe() build = recipe.requestBuild( recipe.daily_build_archive, recipe.owner, list(recipe.distroseries)[0], PackagePublishingPocket.RELEASE) self.assertIs(None, build.manifest) self.assertIs(None, build.getManifestText()) manifest_text = self.factory.makeRecipeText() removeSecurityProxy(build).setManifestText(manifest_text) self.assertEqual(manifest_text, build.getManifestText()) self.assertIsNot(None, build.manifest) IStore(build).flush() manifest_text = self.factory.makeRecipeText() removeSecurityProxy(build).setManifestText(manifest_text) self.assertEqual(manifest_text, build.getManifestText()) removeSecurityProxy(build).setManifestText(None) self.assertIs(None, build.manifest)
def sourcesIncluded(self, direct_inclusion=False): """See `IPackageset`.""" if direct_inclusion == False: source_name_query = ''' SELECT pss.sourcepackagename FROM packagesetsources pss, flatpackagesetinclusion fpsi WHERE pss.packageset = fpsi.child AND fpsi.parent = ? ''' else: source_name_query = ''' SELECT pss.sourcepackagename FROM packagesetsources pss WHERE pss.packageset = ? ''' store = IStore(Packageset) source_names = SQL(source_name_query, (self.id,)) result_set = store.find( SourcePackageName, SourcePackageName.id.is_in(source_names)) return _order_result_set(result_set)
def _getEntry(self, person_id, category_id, product_id=None, distribution_id=None, sourcepackagename_id=None, project_id=None): """Return the KarmaCache entry with the given arguments. Return None if it's not found. """ return IStore(KarmaCache).find( KarmaCache, KarmaCache.personID == person_id, KarmaCache.categoryID == category_id, KarmaCache.productID == product_id, KarmaCache.projectID == project_id, KarmaCache.distributionID == distribution_id, KarmaCache.sourcepackagenameID == sourcepackagename_id).one()
def getOnePOFile(self): """See `ITranslationMessage`.""" from lp.translations.model.pofile import POFile # Get any POFile where this translation exists. # Because we can't create a subselect with "LIMIT" using Storm, # we directly embed a subselect using raw SQL instead. # We can do this because our message sharing code ensures a POFile # exists for any of the sharing templates. # This approach gives us roughly a 100x performance improvement # compared to straightforward join as of 2010-11-11. - danilo pofile = IStore(self).find( POFile, POFile.potemplateID == SQL("""(SELECT potemplate FROM TranslationTemplateItem WHERE potmsgset = %s AND sequence > 0 LIMIT 1)""" % sqlvalues(self.potmsgsetID)), POFile.language == self.language).one() return pofile
def _getFreeBuildersCount(self, processor, virtualized): """How many builders capable of running jobs for the given processor and virtualization combination are idle/free at present?""" query = """ SELECT COUNT(id) FROM builder WHERE builderok = TRUE AND manual = FALSE AND id NOT IN ( SELECT builder FROM BuildQueue WHERE builder IS NOT NULL) AND virtualized = %s """ % sqlvalues(normalize_virtualization(virtualized)) if processor is not None: query += """ AND processor = %s """ % sqlvalues(processor) result_set = IStore(BuildQueue).execute(query) free_builders = result_set.get_one()[0] return free_builders
def getNextJobStatus(cls, packaging): """Return the status of the next job to run.""" store = IStore(TranslationSharingJob) result = store.find( Job, Job.id == TranslationSharingJob.job_id, (TranslationSharingJob.distroseries_id == packaging.distroseries.id), TranslationSharingJob.sourcepackagename_id == packaging.sourcepackagename.id, (TranslationSharingJob.productseries_id == packaging.productseries.id), TranslationSharingJob.job_type == cls.class_job_type, Job._status.is_in([JobStatus.WAITING, JobStatus.RUNNING])) result.order_by(TranslationSharingJob.id) job = result.first() if job is None: return None return job.status
def fetchProjectsForDisplay(self, user): """See `ITranslationGroup`.""" # Avoid circular imports. from lp.registry.model.product import ( get_precached_products, Product, ProductSet, ) products = list(IStore(Product).find( Product, Product.translationgroupID == self.id, Product.active == True, ProductSet.getProductPrivacyFilter(user), ).order_by(Product.display_name)) get_precached_products(products, need_licences=True) icons = bulk.load_related(LibraryFileAlias, products, ['iconID']) bulk.load_related(LibraryFileContent, icons, ['contentID']) return products
def getSimpleUpgrades(distro_series): """See `IDistroSeriesDifferenceSource`. Eager-load related `ISourcePackageName` records. """ differences = IStore(DistroSeriesDifference).find( (DistroSeriesDifference, SourcePackageName), DistroSeriesDifference.derived_series == distro_series, DistroSeriesDifference.difference_type == DistroSeriesDifferenceType.DIFFERENT_VERSIONS, DistroSeriesDifference.status == DistroSeriesDifferenceStatus.NEEDS_ATTENTION, DistroSeriesDifference.parent_source_version != DistroSeriesDifference.base_version, DistroSeriesDifference.source_version == DistroSeriesDifference.base_version, SourcePackageName.id == DistroSeriesDifference.source_package_name_id) return DecoratedResultSet(differences, itemgetter(0))
def getExpiringProducts(cls): """See `ExpirationSourceMixin`.""" earliest_date, latest_date, past_date = cls._get_expiration_dates() recent_jobs = And( ProductJob.job_type == cls.class_job_type, ProductJob.job_id == Job.id, Job.date_created > past_date, ) conditions = [ Product.active == True, CommercialSubscription.productID == Product.id, CommercialSubscription.date_expires >= earliest_date, CommercialSubscription.date_expires < latest_date, Not(Product.id.is_in(Select( ProductJob.product_id, tables=[ProductJob, Job], where=recent_jobs))), ] return IStore(Product).find(Product, *conditions)
def test_revokeByArtifact_specified_grantees(self): # revokeByArtifact() removes the relevant grants for the specified # grantees. artifact = self.factory.makeAccessArtifact() grantee = self.factory.makePerson() someone_else = self.factory.makePerson() grant = self.factory.makeAccessArtifactGrant(artifact=artifact, grantee=grantee) someone_else_grant = self.factory.makeAccessArtifactGrant( artifact=artifact, grantee=someone_else) other_grant = self.factory.makeAccessArtifactGrant() aags = getUtility(IAccessArtifactGrantSource) aags.revokeByArtifact([artifact], [grantee]) IStore(grant).invalidate() self.assertRaises(LostObjectError, getattr, grant, 'grantor') self.assertEqual(someone_else_grant, aags.findByArtifact([artifact])[0]) self.assertIsNot(None, other_grant.grantor)
def findStaleDailyBuilds(): one_day_ago = datetime.now(utc) - timedelta(hours=23, minutes=50) joins = ( SourcePackageRecipe, LeftJoin( SourcePackageRecipeBuild, And( SourcePackageRecipeBuild.recipe_id == SourcePackageRecipe.id, SourcePackageRecipeBuild.archive_id == SourcePackageRecipe.daily_build_archive_id, SourcePackageRecipeBuild.date_created > one_day_ago)), ) return IStore(SourcePackageRecipe).using(*joins).find( SourcePackageRecipe, SourcePackageRecipe.is_stale == True, SourcePackageRecipe.build_daily == True, SourcePackageRecipeBuild.date_created == None, ).config(distinct=True)
def packagesetsForSourceUploader(self, archive, sourcepackagename, person): """See `IArchivePermissionSet`.""" sourcepackagename = self._nameToSourcePackageName(sourcepackagename) store = IStore(ArchivePermission) query = ''' SELECT ap.id FROM archivepermission ap, teamparticipation tp, packagesetsources pss, flatpackagesetinclusion fpsi WHERE ap.person = tp.team AND tp.person = ? AND ap.packageset = fpsi.parent AND pss.packageset = fpsi.child AND pss.sourcepackagename = ? AND ap.archive = ? ''' query = SQL(query, (person.id, sourcepackagename.id, archive.id)) return store.find(ArchivePermission, ArchivePermission.id.is_in(query))
def test_reclaimbranchspace_script(self): # When the reclaimbranchspace script is run, it removes from the file # system any branches that were deleted from the database more than a # week ago. db_branch = self.factory.makeAnyBranch() mirrored_path = self.getBranchPath( db_branch, config.codehosting.mirrored_branches_root) if os.path.exists(mirrored_path): shutil.rmtree(mirrored_path) os.makedirs(mirrored_path) db_branch.destroySelf() transaction.commit() # The first run doesn't remove anything yet. retcode, stdout, stderr = run_script( 'cronscripts/process-job-source.py', ['IReclaimBranchSpaceJobSource']) self.assertEqual('', stdout) self.assertEqual( 'INFO Creating lockfile: /var/lock/' 'launchpad-process-job-source-IReclaimBranchSpaceJobSource.lock\n' 'INFO Running synchronously.\n', stderr) self.assertEqual(0, retcode) self.assertTrue(os.path.exists(mirrored_path)) # Now pretend that the branch was deleted 8 days ago. reclaim_job = IStore(BranchJob).find( BranchJob, BranchJob.job_type == BranchJobType.RECLAIM_BRANCH_SPACE).one() reclaim_job.job.scheduled_start -= datetime.timedelta(days=8) transaction.commit() # The script will now remove the branch from disk. retcode, stdout, stderr = run_script( 'cronscripts/process-job-source.py', ['IReclaimBranchSpaceJobSource']) self.assertEqual('', stdout) self.assertTextMatchesExpressionIgnoreWhitespace( 'INFO Creating lockfile: /var/lock/' 'launchpad-process-job-source-IReclaimBranchSpaceJobSource.lock\n' 'INFO Running synchronously.\n' 'INFO Running <RECLAIM_BRANCH_SPACE branch job \(\d+\) for ' '\d+> \(ID %s\) in status Waiting\n' 'INFO Ran 1 ReclaimBranchSpaceJob jobs.\n' % reclaim_job.job.id, stderr) self.assertEqual(0, retcode) self.assertFalse(os.path.exists(mirrored_path))
def load_teams_and_permissions(grantees): # We now have the grantees we want in the result so load any # associated team memberships and permissions and cache them. if permissions_cache: return store = IStore(cls) for grantee in grantees: grantees_by_id[grantee[0].id] = grantee[0] # Find any teams associated with the grantees. If grantees is a # sliced list (for batching), it may contain indirect grantees but # not the team they belong to so that needs to be fixed below. with_expr = With( "grantees", store.find(cls.grantee_id, cls.policy_id.is_in(policies_by_id.keys())).config( distinct=True)._get_select()) result_set = store.with_(with_expr).find( (TeamParticipation.teamID, TeamParticipation.personID), TeamParticipation.personID.is_in(grantees_by_id.keys()), TeamParticipation.teamID.is_in( Select((SQL("grantees.grantee"), ), tables="grantees", distinct=True))) team_ids = set() direct_grantee_ids = set() for team_id, team_member_id in result_set: if team_member_id == team_id: direct_grantee_ids.add(team_member_id) else: via_teams_cache[team_member_id].append(team_id) team_ids.add(team_id) # Remove from the via_teams cache all the direct grantees. for direct_grantee_id in direct_grantee_ids: if direct_grantee_id in via_teams_cache: del via_teams_cache[direct_grantee_id] # Load and cache the additional required teams. persons = store.find(Person, Person.id.is_in(team_ids)) for person in persons: grantees_by_id[person.id] = person cls._populatePermissionsCache(permissions_cache, shared_artifact_info_types, grantees_by_id.keys(), policies_by_id, grantees_by_id)
def test_run_cronscript(self): # Everything is configured: ZCML, schema-lazr.conf, and security.cfg. product, reviewer = self.make_notification_data() private_branch = self.factory.makeBranch( owner=product.owner, product=product, information_type=InformationType.USERDATA) with person_logged_in(product.owner): product.development_focus.branch = private_branch self.expire_commercial_subscription(product) job = self.JOB_CLASS.create(product, reviewer) # Create a proprietary project owned by a team which will have # different DB relations. team = self.factory.makeTeam( membership_policy=TeamMembershipPolicy.RESTRICTED) proprietary_product = self.factory.makeProduct( owner=team, licenses=[License.OTHER_PROPRIETARY]) self.expire_commercial_subscription(proprietary_product) proprietary_job = self.JOB_CLASS.create(proprietary_product, reviewer) transaction.commit() out, err, exit_code = run_script( "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s" % self.JOB_SOURCE_INTERFACE.getName()) self.addDetail("stdout", Content(UTF8_TEXT, lambda: out)) self.addDetail("stderr", Content(UTF8_TEXT, lambda: err)) self.assertEqual(0, exit_code) self.assertTrue( 'Traceback (most recent call last)' not in err) message = ( '%s has sent email to the maintainer of %s.' % ( self.JOB_CLASS.__name__, product.name)) self.assertTrue( message in err, 'Cound not find "%s" in err log:\n%s.' % (message, err)) message = ( '%s has sent email to the maintainer of %s.' % ( self.JOB_CLASS.__name__, proprietary_product.name)) self.assertTrue( message in err, 'Cound not find "%s" in err log:\n%s.' % (message, err)) IStore(job.job).invalidate() self.assertEqual(JobStatus.COMPLETED, job.job.status) self.assertEqual(JobStatus.COMPLETED, proprietary_job.job.status)
def _nameToPackageset(self, packageset): """Helper to convert a possible string name to IPackageset.""" if isinstance(packageset, basestring): # A package set name was passed, assume the current distro series. ubuntu = getUtility(IDistributionSet).getByName('ubuntu') name = packageset store = IStore(Packageset) packageset = store.find(Packageset, name=name, distroseries=ubuntu.currentseries).one() if packageset is not None: return packageset else: raise NotFoundError("No such package set '%s'" % name) elif IPackageset.providedBy(packageset): return packageset else: raise ValueError('Not a package set: %s' % _extract_type_name(packageset))