コード例 #1
0
ファイル: state.py プロジェクト: pombredanne/conary
    def _readFileList(self, lines, stateVersion, repos):
        configFlagNeeded = []
        autoSourceFlagNeeded = []

        for line in lines[1:]:
            # chop
            line = line[:-1]
            fields = line.split()
            pathId = sha1helper.md5FromString(fields.pop(0))
            version = versions.VersionFromString(fields.pop(-1))

            isConfig = False
            refresh = False

            if stateVersion >= 2:
                info = FileInfo(str=fields.pop())
            elif stateVersion == 1:
                refresh = int(fields.pop(-1))
                isConfig = int(fields.pop(-1))
                info = FileInfo(refresh=refresh, isConfig=isConfig)
            elif stateVersion == 0:
                info = FileInfo()

            fileId = sha1helper.sha1FromString(fields.pop(-1))

            if stateVersion == 0:
                if not isinstance(version, versions.NewVersion):
                    configFlagNeeded.append((pathId, fileId, version))
                    autoSourceFlagNeeded.append((pathId, fileId, version))
            elif stateVersion == 1:
                if not isinstance(version, versions.NewVersion):
                    autoSourceFlagNeeded.append((pathId, fileId, version))

            path = " ".join(fields)

            self.addFile(pathId, path, version, fileId, isConfig=info.isConfig, isAutoSource=info.isAutoSource)
            self.fileNeedsRefresh(pathId, set=info.refresh)

        if configFlagNeeded:
            if not repos:
                raise ConaryStateError(
                    "CONARY file has version %s, but this application cannot convert - please run a cvc command, e.g. cvc diff, to convert."
                    % stateVersion
                )
            assert stateVersion == 0
            fileObjs = repos.getFileVersions(configFlagNeeded)
            for (pathId, fileId, version), fileObj in itertools.izip(configFlagNeeded, fileObjs):
                self.fileIsConfig(pathId, set=fileObj.flags.isConfig())

        if autoSourceFlagNeeded:
            if not repos:
                raise ConaryStateError(
                    "CONARY file has version %s, but this application cannot convert - please run a cvc command, e.g. cvc diff, to convert."
                    % stateVersion
                )
            assert stateVersion < 2
            fileObjs = repos.getFileVersions(autoSourceFlagNeeded)
            for (pathId, fileId, version), fileObj in itertools.izip(autoSourceFlagNeeded, fileObjs):
                self.fileIsAutoSource(pathId, set=fileObj.flags.isAutoSource())
コード例 #2
0
ファイル: chrootcache.py プロジェクト: pombreda/rmake
 def listCached(self):
     items = []
     for name in os.listdir(self.cacheDir):
         if len(name) != (40 + len(self.suffix)
                 ) or not name.endswith(self.suffix):
             continue
         fingerprint = sha1FromString(name[:40])
         st = util.lstat(os.path.join(self.cacheDir, name))
         if st:
             items.append(CachedItem(fingerprint, st.st_atime, st.st_size))
     return items
コード例 #3
0
 def listCached(self):
     items = []
     for name in os.listdir(self.cacheDir):
         if len(name) != (40 + len(self.suffix)) or not name.endswith(
                 self.suffix):
             continue
         fingerprint = sha1FromString(name[:40])
         st = util.lstat(os.path.join(self.cacheDir, name))
         if st:
             items.append(CachedItem(fingerprint, st.st_atime, st.st_size))
     return items
コード例 #4
0
ファイル: filestest.py プロジェクト: sweptr/conary
    def testLinkGroup(self):
        lg1 = sha1helper.sha1FromString('1' * 40)
        lg2 = sha1helper.sha1FromString('2' * 40)
        lg3 = sha1helper.sha1FromString('3' * 40)

        # test creating a new instance from frozen data
        s = files.LinkGroupStream(lg1)
        s2 = files.LinkGroupStream(s.freeze())
        assert(s == s2)

        # test diff
        s2 = files.LinkGroupStream(lg2)
        assert(s != s2)
        diff = s.diff(s2)
        assert(diff == lg1)
        diff2 = s2.diff(s)
        assert(diff2 == lg2)

        # test three way merge
        assert(not s2.twm(diff, s2))
        assert(s == s2)

        # test a failed three way merge
        s3 = files.LinkGroupStream(lg3)
        assert(s2.twm(diff2, s3))

        # test applying a diff that was generated from a linkgroup
        # that is unset (s == None) to a linkgroup that is set.
        # s4 is an unset linkgroup
        s4 = files.LinkGroupStream()
        diff = s4.diff(s)
        # the diff has a special value in this case, "\0"
        assert(diff == "\0")
        assert(not s.twm(diff, s))
        # s should now be unset
        assert(s == s4)
コード例 #5
0
    def getFile(self, auth, path, pathId, fileId, fileV):
        from mimetypes import guess_type
        from conary.lib import sha1helper

        pathId = sha1helper.md5FromString(pathId)
        fileId = sha1helper.sha1FromString(fileId)
        ver = versions.VersionFromString(fileV)

        fileStream = self.repos.getFileVersion(pathId, fileId, ver)
        try:
            contents = self.repos.getFileContents([(fileId, ver)])[0]
        except (errors.FileStreamMissing, errors.FileStreamNotFound):
            return self._write(
                "error", error="The content of that file is not available.")
        except errors.FileHasNoContents, err:
            return self._write("error", error=str(err))
コード例 #6
0
ファイル: repos_web.py プロジェクト: pombr/conary
    def getFile(self, auth, path, pathId, fileId, fileV):
        from mimetypes import guess_type
        from conary.lib import sha1helper

        pathId = sha1helper.md5FromString(pathId)
        fileId = sha1helper.sha1FromString(fileId)
        ver = versions.VersionFromString(fileV)

        fileStream = self.repos.getFileVersion(pathId, fileId, ver)
        try:
            contents = self.repos.getFileContents([(fileId, ver)])[0]
        except (errors.FileStreamMissing, errors.FileStreamNotFound):
            return self._write("error",
                    error="The content of that file is not available.")
        except errors.FileHasNoContents, err:
            return self._write("error", error=str(err))
コード例 #7
0
ファイル: datastore.py プロジェクト: pombreda/conary-1
    def addFile(self, fileObj, hash, precompressed=False, integrityCheck=True):
        path = self.hashToPath(hash)
        self.makeDir(path)
        if os.path.exists(path): return

        tmpFd, tmpName = tempfile.mkstemp(suffix=".new",
                                          dir=os.path.dirname(path))

        realHash = self._writeFile(fileObj, [tmpFd],
                                   precompressed,
                                   computeSha1=integrityCheck)

        if integrityCheck and realHash != sha1helper.sha1FromString(hash):
            os.unlink(tmpName)
            raise errors.IntegrityError

        os.rename(tmpName, path)
コード例 #8
0
ファイル: datastore.py プロジェクト: fedora-conary/conary
    def addFile(self, fileObj, hash, precompressed = False,
                integrityCheck = True):
        path = self.hashToPath(hash)
        self.makeDir(path)
        if os.path.exists(path): return

        tmpFd, tmpName = tempfile.mkstemp(suffix = ".new",
                                          dir = os.path.dirname(path))

        realHash = self._writeFile(fileObj, [ tmpFd ], precompressed,
                                   computeSha1 = integrityCheck)

        if integrityCheck and realHash != sha1helper.sha1FromString(hash):
            os.unlink(tmpName)
            raise errors.IntegrityError

        os.rename(tmpName, path)
コード例 #9
0
ファイル: chrootcache.py プロジェクト: pombreda/rmake
    def findPartialMatch(self, manifest):
        """
        Scan through existing cached chroots for one with a subset of the
        needed troves.

        Returns the fingerprint of the partial match that is closest to
        C{manifest} without any extra troves.
        """
        bestScore = -1
        bestFingerprint = None
        for name in os.listdir(self.cacheDir):
            if len(name) != (40 + len(self.suffix)) or not name.endswith(self.suffix):
                continue
            cached = ChrootManifest.read(os.path.join(self.cacheDir, name))
            if not cached:
                continue
            score = manifest.score(cached)
            if score > bestScore:
                bestScore = score
                bestFingerprint = sha1FromString(name[:40])
        return bestFingerprint
コード例 #10
0
ファイル: repquery.py プロジェクト: pombredanne/crest-1
def _getFileStream(cu, roleIds, fileId):
    cu.execute("""
        SELECT FileStreams.stream
        FROM FileStreams
        JOIN TroveFiles USING (streamId)
        JOIN UserGroupInstancesCache ON
            TroveFiles.instanceId = UserGroupInstancesCache.instanceId
        WHERE FileStreams.stream IS NOT NULL
          AND FileStreams.fileId = ?
          AND UserGroupInstancesCache.userGroupId IN (%(roleids)s)
          LIMIT 1
        """ % { 'roleids' : ", ".join("%d" % x for x in roleIds) },
        cu.binary(sha1FromString(fileId)))

    l = list(cu)
    if not l:
        return None

    bin = cu.frombinary(l[0][0])
    if bin is not None:
        return files.ThawFile(bin, None)
    return None
コード例 #11
0
    def findPartialMatch(self, manifest):
        """
        Scan through existing cached chroots for one with a subset of the
        needed troves.

        Returns the fingerprint of the partial match that is closest to
        C{manifest} without any extra troves.
        """
        bestScore = -1
        bestFingerprint = None
        for name in os.listdir(self.cacheDir):
            if len(name) != (40 + len(self.suffix)) or not name.endswith(
                    self.suffix):
                continue
            cached = ChrootManifest.read(os.path.join(self.cacheDir, name))
            if not cached:
                continue
            score = manifest.score(cached)
            if score > bestScore:
                bestScore = score
                bestFingerprint = sha1FromString(name[:40])
        return bestFingerprint
コード例 #12
0
ファイル: repquery.py プロジェクト: pombreda/crest
def _getFileStream(cu, roleIds, fileId):
    cu.execute("""
        SELECT FileStreams.stream
        FROM FileStreams
        JOIN TroveFiles USING (streamId)
        JOIN UserGroupInstancesCache ON
            TroveFiles.instanceId = UserGroupInstancesCache.instanceId
        WHERE FileStreams.stream IS NOT NULL
          AND FileStreams.fileId = ?
          AND UserGroupInstancesCache.userGroupId IN (%(roleids)s)
          LIMIT 1
        """ % { 'roleids' : ", ".join("%d" % x for x in roleIds) },
        cu.binary(sha1FromString(fileId)))

    l = list(cu)
    if not l:
        return None

    bin = cu.frombinary(l[0][0])
    if bin is not None:
        return files.ThawFile(bin, None)
    return None
コード例 #13
0
ファイル: datastore.py プロジェクト: fedora-conary/conary
    def addFile(self, f, hash, precompressed = False):
        tmpFileList = []
        for store in self.stores:
            path = self.hashToPath(hash)
            store.makeDir(path)
            if os.path.exists(path): return

            tmpFd, tmpPath = tempfile.mkstemp(suffix = ".new",
                                              dir = os.path.dirname(path))
            tmpFileList.append((tmpFd, tmpPath, path))

        # fd's close as a side effect. yikes.
        realHash = self._writeFile(f, [ x[0] for x in tmpFileList ],
                                   precompressed, computeSha1 = True)

        if realHash != sha1helper.sha1FromString(hash):
            for fd, tmpPath, path in tmpFileList:
                os.unlink(tmpPath)

            raise errors.IntegrityError

        for fd, tmpPath, path in tmpFileList:
            os.rename(tmpPath, path)
コード例 #14
0
ファイル: datastore.py プロジェクト: pombreda/conary-1
    def addFile(self, f, hash, precompressed=False):
        tmpFileList = []
        for store in self.stores:
            path = self.hashToPath(hash)
            store.makeDir(path)
            if os.path.exists(path): return

            tmpFd, tmpPath = tempfile.mkstemp(suffix=".new",
                                              dir=os.path.dirname(path))
            tmpFileList.append((tmpFd, tmpPath, path))

        # fd's close as a side effect. yikes.
        realHash = self._writeFile(f, [x[0] for x in tmpFileList],
                                   precompressed,
                                   computeSha1=True)

        if realHash != sha1helper.sha1FromString(hash):
            for fd, tmpPath, path in tmpFileList:
                os.unlink(tmpPath)

            raise errors.IntegrityError

        for fd, tmpPath, path in tmpFileList:
            os.rename(tmpPath, path)
コード例 #15
0
 def _digest(rpmlibHeader):
     if rpmhelper.SIG_SHA1 in rpmlibHeader.keys():
         return sha1helper.sha1FromString(rpmlibHeader[rpmhelper.SIG_SHA1])
     else:
         return None
コード例 #16
0
 def setFromString(self, hexdigest):
     StringStream.set(self, sha1helper.sha1FromString(hexdigest))
コード例 #17
0
ファイル: state.py プロジェクト: tensor5/conary
    def _readFileList(self, lines, stateVersion, repos):
        configFlagNeeded = []
        autoSourceFlagNeeded = []

        for line in lines[1:]:
            # chop
            line = line[:-1]
            fields = line.split()
            pathId = sha1helper.md5FromString(fields.pop(0))
            version = versions.VersionFromString(fields.pop(-1))

            isConfig = False
            refresh = False

            if stateVersion >= 2:
                info = FileInfo(str=fields.pop())
            elif stateVersion == 1:
                refresh = int(fields.pop(-1))
                isConfig = int(fields.pop(-1))
                info = FileInfo(refresh=refresh, isConfig=isConfig)
            elif stateVersion == 0:
                info = FileInfo()

            fileId = sha1helper.sha1FromString(fields.pop(-1))

            if stateVersion == 0:
                if not isinstance(version, versions.NewVersion):
                    configFlagNeeded.append((pathId, fileId, version))
                    autoSourceFlagNeeded.append((pathId, fileId, version))
            elif stateVersion == 1:
                if not isinstance(version, versions.NewVersion):
                    autoSourceFlagNeeded.append((pathId, fileId, version))

            path = " ".join(fields)

            self.addFile(pathId,
                         path,
                         version,
                         fileId,
                         isConfig=info.isConfig,
                         isAutoSource=info.isAutoSource)
            self.fileNeedsRefresh(pathId, set=info.refresh)

        if configFlagNeeded:
            if not repos:
                raise ConaryStateError(
                    'CONARY file has version %s, but this application cannot convert - please run a cvc command, e.g. cvc diff, to convert.'
                    % stateVersion)
            assert (stateVersion == 0)
            fileObjs = repos.getFileVersions(configFlagNeeded)
            for (pathId, fileId, version), fileObj in \
                            itertools.izip(configFlagNeeded, fileObjs):
                self.fileIsConfig(pathId, set=fileObj.flags.isConfig())

        if autoSourceFlagNeeded:
            if not repos:
                raise ConaryStateError(
                    'CONARY file has version %s, but this application cannot convert - please run a cvc command, e.g. cvc diff, to convert.'
                    % stateVersion)
            assert (stateVersion < 2)
            fileObjs = repos.getFileVersions(autoSourceFlagNeeded)
            for (pathId, fileId, version), fileObj in \
                            itertools.izip(autoSourceFlagNeeded, fileObjs):
                self.fileIsAutoSource(pathId, set=fileObj.flags.isAutoSource())
コード例 #18
0
class CapsuleTest(rephelp.RepositoryHelper):

    id1 = md5FromString("00010001000100010001000100010001")
    id2 = md5FromString("00010001000100010001000100010002")
    id3 = md5FromString("00010001000100010001000100010003")
    id4 = md5FromString("00010001000100010001000100010004")
    id5 = md5FromString("00010001000100010001000100010005")

    fid1 = sha1FromString("1001000100010001000100010001000100010001")
    fid2 = sha1FromString("1001000100010001000100010001000100010002")
    fid3 = sha1FromString("1001000100010001000100010001000100010003")
    fid4 = sha1FromString("1001000100010001000100010001000100010004")
    fid5 = sha1FromString("1001000100010001000100010001000100010005")

    v1 = versions.ThawVersion('/localhost@foo:bar/1.0:1.0-1-1')

    @conary_test.rpm
    def test01_Trove(self):
        t = trove.Trove('foo:continer', self.v1, deps.Flavor())
        t.addFile(self.id1, '/1', self.v1, self.fid1)
        t.addFile(self.id2, '/2', self.v1, self.fid2)
        h = { rpmhelper.NAME    : 'foorpm',
              rpmhelper.VERSION : '1.0',
              rpmhelper.RELEASE : '1',
              rpmhelper.ARCH    : 'i386',
              rpmhelper.EPOCH   : [ 1 ] }
        t.addRpmCapsule('foo.rpm', self.v1, self.fid5, h)

        assert([ x[1] for x in t.iterFileList() ] ==
                    [ '/1', '/2'] )
        assert([ x[1] for x in t.iterFileList(members = True) ] ==
                    [ '/1', '/2'] )
        assert([ x[0:2] for x in t.iterFileList(capsules = True) ] ==
                    [ (trove.CAPSULE_PATHID, 'foo.rpm' ) ] )
        assert([ x[1] for x in t.iterFileList(members = True,
                                              capsules = True) ] ==
                    [ '/1', 'foo.rpm', '/2' ])
        assert([ x[1] for x in t.iterFileList(members = False,
                                              capsules = False) ] == [])

    @conary_test.rpm
    @testhelp.context('rollback')
    def test02_Repository(self):
        def csContents(repos, job):
            p = os.path.join(self.workDir, 'foo.ccs')
            repos.createChangeSetFile(job, p)
            fc = filecontainer.FileContainer(
                                    util.ExtendedFile(p, buffering = False))
            l = []
            info = fc.getNextFile()
            while info:
                l.append(info)
                info = fc.getNextFile()

            return l

        cmp = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm')
        repos = self.openRepository()
        reposCmp = repos.getTrove(*cmp.getNameVersionFlavor())
        assert(reposCmp == cmp)
        l = csContents(repos, [ ("simple:rpm", (None, None),
                                cmp.getNameVersionFlavor()[1:], True) ])
        assert([ x[0][0:16] for x in l ] ==
               ['CONARYCHANGESET',
                '\x8d\xeb\xb9\x15M!\xe0\xc5\x08D\x87\xf7\xe1\xf9fW',
                trove.CAPSULE_PATHID ])
        cmp = self.addRPMComponent("simple:rpm=1.1", 'simple-1.1-1.i386.rpm')

        self.updatePkg('simple:rpm=1.0')
        assert(os.path.isdir(self.rootDir + "/dir"))
        self.verifyFile(self.rootDir + "/config", "config\n")
        self.verifyFile(self.rootDir + "/normal", "normal\n")

        self.updatePkg('simple:rpm=1.1')
        self.verifyFile(self.rootDir + "/config", "changed-config\n")
        self.verifyFile(self.rootDir + "/normal", "changed-normal\n")

        self.rollback(self.rootDir, 1)
        self.verifyFile(self.rootDir + "/config", "config\n")
        self.verifyFile(self.rootDir + "/normal", "normal\n")

        self.writeFile(self.rootDir + '/config', 'config\nlocal config\n')
        rc, str = self.captureOutput(self.updatePkg, 'simple:rpm=1.1')
        self.assertEquals(str, 'warning: /config saved as /config.rpmsave\n')
        self.verifyFile(self.rootDir + '/config', 'changed-config\n')
        self.rollback(self.rootDir, 1)
        self.verifyFile(self.rootDir + '/config', 'config\nlocal config\n')

        rc, str = self.captureOutput(self.erasePkg, self.rootDir, 'simple:rpm')
        self.assertEquals(str, 'warning: /config saved as /config.rpmsave\n')
        assert(not os.path.exists(self.rootDir + '/config'))
        self.rollback(self.rootDir, 1)
        self.verifyFile(self.rootDir + '/config', 'config\nlocal config\n')

        rc, str = self.captureOutput(self.rollback, self.rootDir, 0)
        self.assertEquals(str, 'warning: /config saved as /config.rpmsave\n')
        assert(not os.path.exists(self.rootDir + "/dir"))
        assert(not os.path.exists(self.rootDir + "/config"))
        assert(not os.path.exists(self.rootDir + "/normal"))

    @conary_test.rpm
    @testhelp.context('rollback')
    def test03_Overlap(self):
        osA1 = self.addRPMComponent("overlap-same-A:rpm=1.0",
                                    'overlap-same-A-1.0-1.i386.rpm')
        osB1 = self.addRPMComponent("overlap-same-B:rpm=1.0",
                                    'overlap-same-B-1.0-1.i386.rpm')
        self.updatePkg('overlap-same-A:rpm=1.0')
        self.updatePkg('overlap-same-B:rpm=1.0')
        assert(os.path.exists(self.rootDir + '/A-1'))
        assert(os.path.exists(self.rootDir + '/B-1'))
        self.checkOwners('/file', [ osA1, osB1 ])

        self.erasePkg(self.rootDir, 'overlap-same-B:rpm')
        assert(os.path.exists(self.rootDir + '/A-1'))
        assert(os.path.exists(self.rootDir + '/file'))
        self.checkOwners('/file', [ osA1 ])

        self.rollback(2)
        self.checkOwners('/file', [ osA1, osB1 ])

        self.rollback(1)
        self.checkOwners('/file', [ osA1 ])

    @conary_test.rpm
    def test04_DirectoryPreexisting(self):
        self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm')
        os.mkdir(self.rootDir + '/dir')
        self.updatePkg('simple:rpm')
        assert(os.path.exists(self.rootDir + '/normal'))

    @conary_test.rpm
    def test05_NoJobSplitting(self):
        self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm')
        self.addRPMComponent("ownerships:rpm=1.0", 'ownerships-1.0-1.i386.rpm')

        try:
            old = self.cfg.updateThreshold
            self.cfg.updateThreshold = 1
            rc, txt = self.captureOutput(self.updatePkg,
                                         [ 'simple:rpm', 'ownerships:rpm' ],
                                         raiseError=True, info=True)

            # if job splitting happens you get "Job 1 of 2" here because of the
            # small updateThreashold
            self.assertEquals(txt, '    Install ownerships:rpm=1.0-1-1\n'
                                   '    Install simple:rpm=1.0-1-1\n')

            # make sure having a critical update doesn't make the splitting
            # break
            criticalUpdateInfo = updatecmd.CriticalUpdateInfo()
            criticalUpdateInfo.setCriticalTroveRegexps(['simple:rpm'])
            itemsList = [
                ('simple:rpm', (None, None), (None, None), True),
                ('ownerships:rpm', (None, None), (None, None), True),
            ]
            client = conaryclient.ConaryClient(self.cfg)
            updJob = client.newUpdateJob()
            client.prepareUpdateJob(updJob, itemsList, migrate=True,
                                    criticalUpdateInfo = criticalUpdateInfo)
        finally:
            self.cfg.updateThreshold = old

        # info components should get split out of course CNY-3387
        self.addComponent("info-disk:user=1.0")
        rc, txt = self.captureOutput(self.updatePkg,
                        [ 'simple:rpm', 'info-disk:user' ], info = True )
        self.assertEquals(txt,
            'Job 1 of 2:\n'
            '    Install info-disk:user=1.0-1-1\n'
            'Job 2 of 2:\n'
            '    Install simple:rpm=1.0-1-1\n')

    @conary_test.rpm
    def test06_GhostPreexisting(self):
        self.addRPMComponent("ghost:rpm=1.0", 'ghost-1.0-1.i386.rpm')
        os.mkdir(self.rootDir + '/foo')
        self.writeFile(self.rootDir + '/foo/ghost', 'orig contents')
        rc, str = self.captureOutput(self.updatePkg, 'ghost:rpm')
        assert(not str)
        self.verifyFile(self.rootDir + '/foo/ghost', 'orig contents')

    @conary_test.rpm
    def test07_BadRpmCapsule(self):
        cmp = self.addRPMComponent("ghost:rpm=1.0", 'epoch-1.0-1.i386.rpm')
        repos = self.openRepository()
        orig = self.workDir + '/ghost.ccs'
        modified = self.workDir + '/ghost-new.ccs'
        repos.createChangeSetFile([ (cmp.getName(), (None, None),
                                     cmp.getNameVersionFlavor()[1:],
                                     True) ], orig)
        fc = filecontainer.FileContainer(
                                util.ExtendedFile(orig, buffering = False))
        newFc = filecontainer.FileContainer(
                        util.ExtendedFile(modified, "w", buffering = False))
        # CONARYCHANGESET
        (name, tag, contents) = fc.getNextFile()
        newFc.addFile(name, filecontents.FromFile(contents), tag,
                      precompressed = True)
        # the RPM
        (name, tag, contents) = fc.getNextFile()
        contents = filecontents.FromString("busted!")
        newFc.addFile(name, contents, tag)
        cs = changeset.ChangeSetFromFile(modified)
        # this throws away the output about the install failing
        self.assertRaises(files.Sha1Exception, self.captureOutput,
                          self.updatePkg, self.rootDir, cs)

    @conary_test.rpm
    @testhelp.context('sysmodel', 'rollback')
    def test08_OverlapConflict(self):
        osA1 = self.addRPMComponent("overlap-same-A:rpm=1.0",
                                    'overlap-same-A-1.0-1.i386.rpm')
        self.addCollection('overlap-same-A', '1.0', [ ':rpm' ])
        osB1 = self.addRPMComponent("overlap-conflict:rpm",
                                    'overlap-conflict-1.0-1.i386.rpm')
        self.addCollection('overlap-conflict', '1.0', [ ':rpm' ])
        self.updatePkg('overlap-same-A:rpm=1.0')
        self.assertRaises(update.UpdateError,
            self.updatePkg, 'overlap-conflict:rpm=1.0', raiseError=True)

        self.updatePkg('overlap-conflict:rpm=1.0', replaceFiles = True)
        self.checkOwners('/file', [ osB1 ])
        self.rollback(1)
        self.checkOwners('/file', [ osA1 ])

        # now test that allowing overlaps via groups pathConflicts is OK
        # in system model
        self.addCollection('group-dist', '1.0', [
            ('overlap-same-A:rpm', '1.0'),
            ('overlap-conflict:rpm', '1.0')],
            pathConflicts=['/file'])

        root = self.cfg.root
        util.mkdirChain(root+'/etc/conary')
        file(root+'/etc/conary/system-model', 'w').write(
            'install group-dist=localhost@rpl:linux/1.0\n')
        model = cml.CML(self.cfg)
        modelFile = systemmodel.SystemModelFile(model)
        updatecmd.doModelUpdate(self.cfg, model, modelFile, [],
            keepExisting=True)



        self.resetRoot()
        self.updatePkg(['overlap-same-A:rpm',
                        'overlap-conflict:rpm=1.0'], replaceFiles = True)
        self.rollback(0)

    @conary_test.rpm
    def test08_CapsuleTroveDisplay(self):
        cmp = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm')
        repos = self.openRepository()
        cs = repos.createChangeSet([ (cmp.getName(), (None, None),
                                      cmp.getNameVersionFlavor()[1:], True) ])

        db = self.openDatabase()
        self.updatePkg('simple:rpm')

        for method, args in [
                (showchangeset.displayChangeSet, (None, cs, None, self.cfg) ),
                (queryrep.displayTroves, (self.cfg, [ "simple:rpm" ]) ),
                (query.displayTroves, (db, self.cfg, [ "simple:rpm" ]) ) ]:
            rc, res = self.captureOutput(method, ls = True, *args)
            self.assertEquals(res, '/config\n/dir\n/normal\n')

            rc, res = self.captureOutput(method, capsules = True, ls = True,
                                         *args)
            self.assertEquals(res, 'simple-1.0-1.i386.rpm\n')

    @conary_test.rpm
    def test09_CapsuleInstallFlags(self):
        # test some random flags, like --test, --justdb, and
        # --replace-unmanaged-files
        cmp = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm')
        self.updatePkg('simple:rpm', test = True)
        assert(not os.path.exists(self.rootDir + '/normal'))
        assert(not self.owners('/normal'))
        str = os.popen('rpm --root %s -qa' % self.rootDir).readlines()
        assert(not str)

        self.updatePkg('simple:rpm', justDatabase = True)
        assert(len(self.owners('/normal')) == 1)
        assert(not os.path.exists(self.rootDir + '/normal'))
        str = os.popen('rpm --root %s -qa' % self.rootDir).readlines()
        self.assertEquals(str, [ 'simple-1.0-1.i386\n' ])
        rc, str = self.captureOutput(self.erasePkg, self.rootDir,
                                     'simple:rpm',
                                     justDatabase = True)
        self.assertEquals(str,
            'warning: cannot remove /normal: No such file or directory\n'
            'warning: cannot remove /config: No such file or directory\n'
            'warning: cannot remove /dir: No such file or directory\n')
        str = os.popen('rpm --root %s -qa' % self.rootDir).readlines()
        self.assertEquals(str, [])
        assert(not self.owners('/normal'))

        self.writeFile(self.rootDir + '/normal', 'placeholder')
        rc, str = self.captureOutput(self.updatePkg, 'simple:rpm')
        self.assertEquals(str,
                'error: changeset cannot be applied:\n'
                'applying update would cause errors:\n'
                '/normal is in the way of a newly created file in '
                        'simple:rpm=/localhost@rpl:linux/1.0-1-1[]\n')
        rc, str = self.captureOutput(self.updatePkg, 'simple:rpm',
                                     replaceUnmanagedFiles = True)
        self.assertEquals(str, '')
        self.verifyFile(self.rootDir + '/normal', 'normal\n')

        self.resetRoot()

        self.updatePkg('simple:rpm', justDatabase = True, skipCapsuleOps = True)
        assert(len(self.owners('/normal')) == 1)
        assert(not os.path.exists(self.rootDir + '/normal'))
        str = os.popen('rpm --root %s -qa' % self.rootDir).readlines()
        self.assertEquals(str, [ ])
        # syncCapsuleDatabase would helpfully erase the trove before we get a
        # chance to do the same thing, so turn it off for this test
        self.cfg.syncCapsuleDatabase = 'false'
        try:
            rc, str = self.captureOutput(self.erasePkg, self.rootDir,
                                     'simple:rpm',
                                     justDatabase = True,
                                     skipCapsuleOps = True)
        finally:
            self.cfg.resetToDefault('syncCapsuleDatabase')
        self.assertEquals(str,
            'warning: cannot remove /normal: No such file or directory\n'
            'warning: cannot remove /config: No such file or directory\n'
            'warning: cannot remove /dir: No such file or directory\n')
        str = os.popen('rpm --root %s -qa' % self.rootDir).readlines()
        self.assertEquals(str, [])
        assert(not self.owners('/normal'))

    @conary_test.rpm
    def test10_UnchangedRPM(self):
        cmp = self.addRPMComponent("simple:rpm=1.0-1-1",
                                   'simple-1.0-1.i386.rpm')
        cmp = self.addRPMComponent("simple:rpm=1.0-1-2",
                                   'simple-1.0-1.i386.rpm')
        self.updatePkg('simple:rpm=1.0-1-1')
        self.updatePkg('simple:rpm=1.0-1-2')
        # this makes sure the right version is installed
        self.erasePkg(self.rootDir, 'simple:rpm=1.0-1-2')

    @conary_test.rpm
    def test11_UnchangedUpdate(self):
        # CNY-3335
        simple10  = self.addRPMComponent("simple:rpm=1.0-1-1",
                                         'simple-1.0-1.i386.rpm')
        simple101 = self.addRPMComponent("simple:rpm=1.0.1-1-1",
                                         'simple-1.0.1-1.i386.rpm',
                                         versus = simple10)
        self.updatePkg('simple:rpm=1.0-1-1')
        self.updatePkg('simple:rpm=1.0.1-1-1')

    @conary_test.rpm
    def test_unchangedFileid(self):
        # CNY-3719
        simple10  = self.addRPMComponent("simple:rpm=1.0-1-1",
                                         'simple-1.0-1.i386.rpm')
        # Commit a new version so all the file versions are new
        simple11 = self.addRPMComponent("simple:rpm=1.1-1-1",
                                         'simple-1.1-1.i386.rpm',
                                         versus = simple10)
        # Now go back to the old fileids, the filevers will be new again
        simple101  = self.addRPMComponent("simple:rpm=1.0.1-1-1",
                                         'simple-1.0.1-1.i386.rpm',
                                         versus = simple11)
        self.updatePkg('simple:rpm=1.0-1-1')
        self.updatePkg('simple:rpm=1.0.1-1-1')

    @conary_test.rpm
    def test12_TroveZeroEpoch(self):
        t = trove.Trove('foo:continer', self.v1, deps.Flavor())
        t.addFile(self.id1, '/1', self.v1, self.fid1)
        t.addFile(self.id2, '/2', self.v1, self.fid2)
        h = { rpmhelper.NAME    : 'foorpm',
              rpmhelper.VERSION : '1.0',
              rpmhelper.RELEASE : '1',
              rpmhelper.ARCH    : 'i386',
              rpmhelper.EPOCH   : [ 0 ] }
        t.addRpmCapsule('foo.rpm', self.v1, self.fid5, h)

        self.assertEqual(t.troveInfo.capsule.rpm.name(), 'foorpm')
        self.assertEqual(t.troveInfo.capsule.rpm.epoch(), 0)
        self.assertEqual(t.troveInfo.capsule.rpm.version(), '1.0')
        self.assertEqual(t.troveInfo.capsule.rpm.release(), '1')
        self.assertEqual(t.troveInfo.capsule.rpm.arch(), 'i386')

    @conary_test.rpm
    def testChangesetExploder(self):
        simple10  = self.addRPMComponent("simple:rpm=1.0-1-1",
                                         'simple-1.0-1.i386.rpm')
        repos = self.openRepository()
        cs = repos.createChangeSet([
            (simple10.getName(), (None, None),
             simple10.getNameVersionFlavor()[1:], True) ])
        changeset.ChangesetExploder(cs, self.rootDir)
        assert(os.path.isdir(self.rootDir + '/dir'))
        self.assertEquals(
            os.stat(self.rootDir + '/normal').st_size, 7)

    @conary_test.rpm
    @testhelp.context('rollback')
    def testRpmFileColoring(self):
        if os.uname()[4] != 'x86_64':
            # this test only works on x86_64 platforms
            return

        i386md5 = '0fc54eafb8daf886ff7d43c4448acc71'
        x64md5 = '4cb13908ca1d7989be493c581a6fa1d3'

        oldtrv  = self.addRPMComponent("tmpwatch:rpm=0.1-1-1",
                                       'tmpwatch-2.9.1-1.i386.rpm')
        i386trv  = self.addRPMComponent("tmpwatch:rpm=1.0-1-1",
                                        'tmpwatch-2.9.7-1.1.el5.2.i386.rpm')
        x64trv  = self.addRPMComponent("tmpwatch:rpm=2.0-1-1",
                                       'tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm')

        self.updatePkg('tmpwatch:rpm=1.0-1-1')
        self.checkMd5('/usr/sbin/tmpwatch', i386md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ i386trv ])
        self.updatePkg('tmpwatch:rpm=2.0-1-1', keepExisting = True)
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ x64trv ])
        self.erasePkg(self.rootDir, 'tmpwatch:rpm=2.0-1-1')
        # it's a shame we don't restore the file here
        assert(not os.path.exists(self.rootDir + '/usr/sbin/tmpwatch'))
        self.rollback(2)
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.rollback(1)
        self.checkMd5('/usr/sbin/tmpwatch', i386md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ i386trv ])

        self.resetRoot()
        self.updatePkg('tmpwatch:rpm=2.0-1-1')
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ x64trv ])
        self.updatePkg('tmpwatch:rpm=1.0-1-1', keepExisting = True)
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ x64trv ])
        self.erasePkg(self.rootDir, 'tmpwatch:rpm=1.0-1-1')
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)

        self.resetRoot()
        self.updatePkg([ 'tmpwatch:rpm=1.0-1-1', 'tmpwatch:rpm=2.0-1-1' ])
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ x64trv ])

        # this still causes conflicts
        rc, str = self.captureOutput(self.updatePkg, 'tmpwatch:rpm=0.1')
        assert('conflicts' in str)

    @conary_test.rpm
    def testFileColorUsedByScript(self):
        """
        Post script references a file that is being "shared" in the same job

        @tests: CNY-3884
        """
        if os.uname()[4] != 'x86_64':
            # this test only works on x86_64 platforms
            return

        i386md5 = '0fc54eafb8daf886ff7d43c4448acc71'
        x64md5 = '4cb13908ca1d7989be493c581a6fa1d3'

        i386trv = self.addRPMComponent("tmpwatch:rpm=1.0-1-1",
                'tmpwatch-2.9.7-1.1.el5.2.i386.rpm')
        x64trv = self.addRPMComponent("tmpwatch:rpm=2.0-1-1",
                'tmpwatch-2.9.7-1.1.el5.2.x86_64.rpm')
        consumer = self.addRPMComponent('usetmpwatch:rpm=1.0-1-1',
                'usetmpwatch-1.0-1.x86_64.rpm')

        self.updatePkg('tmpwatch:rpm=2.0-1-1')
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ x64trv ])
        rc, out = self.captureOutput(self.updatePkg,
                ['tmpwatch:rpm=1.0-1-1', 'usetmpwatch:rpm'],
                keepExisting=True)
        self.checkMd5('/usr/sbin/tmpwatch', x64md5)
        self.checkOwners('/usr/sbin/tmpwatch',  [ x64trv ])
        self.assertEqual(out, 'PRESENT\n')

    @conary_test.rpm
    @testhelp.context('rollback')
    def test14_testRpmSharedHardLinks(self):
        # we build fro msource here rather than use addRPMComponent to get
        # the hard links right
        recipestr1 = r"""
class HardLinks(CapsuleRecipe):
    name = 'hardlinkconflict'
    version = '%s'
    clearBuildReqs()

    def setup(r):
        r.addCapsule('%s')
"""
        built, d = self.buildRecipe(
            recipestr1 % ('1.0_1',
                          'hardlinkconflict-1.0-1.x86_64.rpm'), "HardLinks")
        built, d = self.buildRecipe(
            recipestr1 % ('1.0_2',
                          'hardlinkconflict-1.0-2.x86_64.rpm'), "HardLinks")

        self.updatePkg('hardlinkconflict=1.0_1')
        self.updatePkg('hardlinkconflict=1.0_2', keepExisting = True)
        assert(len(self.owners('/foo')) == 2)
        self.erasePkg(self.rootDir, 'hardlinkconflict=1.0_2')
        assert(len(self.owners('/foo')) == 1)

        self.resetRoot()
        self.updatePkg([ 'hardlinkconflict=1.0_1', 'hardlinkconflict=1.0_2' ])
        assert(len(self.owners('/foo')) == 2)
        self.erasePkg(self.rootDir, 'hardlinkconflict=1.0_2')
        assert(len(self.owners('/foo')) == 1)

    @conary_test.rpm
    def test15_SetupHandling(self):
        oldTrv  = self.addRPMComponent("setup:rpm=0.1-1-1",
                                       'setup-2.5.58-7.el5.noarch.rpm')
        self.resetRoot()
        util.mkdirChain(self.rootDir + '/etc')
        self.writeFile(self.rootDir + '/etc/passwd',
                       "passwd junk\n"
                       "root:wrong rootuser\n")
        self.writeFile(self.rootDir + '/etc/group',
                       "group junk\n"
                       "root:wrong root group\n")
        self.updatePkg('setup:rpm', replaceFiles = True)

        p = open(self.rootDir + '/etc/passwd').readlines()
        self.assertEquals(p[0], 'root:*:0:0:root:/root:/bin/bash\n')
        self.assertEquals(p[-1], 'passwd junk\n')
        assert(not os.path.exists(self.rootDir + '/etc/passwd.rpmnew'))

        p = open(self.rootDir + '/etc/group').readlines()
        self.assertEquals(p[0], 'root::0:root\n')
        self.assertEquals(p[-1], 'group junk\n')
        assert(not os.path.exists(self.rootDir + '/etc/group.rpmnew'))

    @conary_test.rpm
    def testScriptFailures(self):
        'test what happens when RPM scripts fail'
        # CNY-3454
        f = self.addRPMComponent('aaa_first:rpm=1.0-1-1',
                                 'aaa_first-1.0-1.noarch.rpm')
        f = self.addRPMComponent('failpost:rpm=1.0-1-1',
                                 'failpost-1.0-1.noarch.rpm')
        f = self.addRPMComponent('failpostun:rpm=1.0-1-1',
                                 'failpostun-1.0-1.noarch.rpm')
        f = self.addRPMComponent('failpre:rpm=1.0-1-1',
                                 'failpre-1.0-1.noarch.rpm')
        f = self.addRPMComponent('failpreun:rpm=1.0-1-1',
                                 'failpreun-1.0-1.noarch.rpm')
        f = self.addRPMComponent('zzz_last:rpm=1.0-1-1',
                                 'zzz_last-1.0-1.noarch.rpm')
        f == f

        self.updatePkg('aaa_first:rpm=1.0-1-1')
        self.checkOrdering('aaa_first-1.0-1.noarch')
        self.verifyFile(self.rootDir + '/dummy/aaa_first')
        util.mkdirChain(self.rootDir+'/var/tmp')
        rc, str = self.captureOutput(self.updatePkg, 'failpost:rpm=1.0-1-1')
        self.assertEquals(str,
            'warning: %post(failpost-1.0-1.noarch) scriptlet failed, exit status 127\n')
        self.checkOrdering('failpost-1.0-1.noarch')
        self.assertEquals(rc, None)
        self.verifyFile(self.rootDir + '/dummy/file')
        self.updatePkg('zzz_last:rpm=1.0-1-1')
        self.checkOrdering('zzz_last-1.0-1.noarch')
        self.verifyFile(self.rootDir + '/dummy/zzz_last')
        self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp')


        rc, str = self.captureOutput(self.updatePkg,
                       ['aaa_first:rpm=1.0-1-1',
                        'failpost:rpm=1.0-1-1',
                        'zzz_last:rpm=1.0-1-1'])
        self.assertEquals(str,
            'warning: %post(failpost-1.0-1.noarch) scriptlet failed, exit status 127\n')
        self.assertEquals(rc, None)
        self.checkOrdering('aaa_first-1.0-1.noarch'
                           ' failpost-1.0-1.noarch'
                           ' zzz_last-1.0-1.noarch')
        self.verifyFile(self.rootDir + '/dummy/aaa_first')
        self.verifyFile(self.rootDir + '/dummy/file')
        self.verifyFile(self.rootDir + '/dummy/zzz_last')
        self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp')

        self.updatePkg(['aaa_first:rpm=1.0-1-1',
                        'failpostun:rpm=1.0-1-1',
                        'zzz_last:rpm=1.0-1-1'])
        self.verifyFile(self.rootDir + '/dummy/aaa_first')
        self.verifyFile(self.rootDir + '/dummy/file')
        self.checkOrdering('aaa_first-1.0-1.noarch'
                           ' failpostun-1.0-1.noarch'
                           ' zzz_last-1.0-1.noarch')
        rc, str = self.captureOutput(self.erasePkg, self.rootDir,
            'failpostun:rpm=1.0-1-1')
        self.assertEquals(str,
            'warning: %postun(failpostun-1.0-1.noarch) scriptlet failed, exit status 127\n')
        self.verifyNoFile(self.rootDir + '/dummy/file')
        self.verifyFile(self.rootDir + '/dummy/zzz_last')
        self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp')

        rc, str = self.captureOutput(self.updatePkg,
                        ['aaa_first:rpm=1.0-1-1',
                        'failpre:rpm=1.0-1-1',
                        'zzz_last:rpm=1.0-1-1'])
        self.assertEquals(str, '\n'.join((
          'error: %pre(failpre-1.0-1.noarch) scriptlet failed, exit status 127',
          'error: install: %pre scriptlet failed (2), skipping failpre-1.0-1',
          'error: RPM failed to install requested packages: failpre-1.0-1.noarch',
          '')))
        self.assertEquals(rc, None)
        self.checkOrdering('aaa_first-1.0-1.noarch'
                           ' failpre-1.0-1.noarch'
                           ' zzz_last-1.0-1.noarch')
        self.verifyFile(self.rootDir + '/dummy/aaa_first')
        self.verifyNoFile(self.rootDir + '/dummy/file')
        self.verifyFile(self.rootDir + '/dummy/zzz_last')
        self.resetRoot(); util.mkdirChain(self.rootDir+'/var/tmp')

        rc, str = self.captureOutput(self.updatePkg,
                       ['aaa_first:rpm=1.0-1-1',
                        'failpreun:rpm=1.0-1-1',
                        'zzz_last:rpm=1.0-1-1'])
        self.assertEquals(rc, None)
        self.assertEquals(str, '')
        self.checkOrdering('aaa_first-1.0-1.noarch'
                           ' failpreun-1.0-1.noarch'
                           ' zzz_last-1.0-1.noarch')
        self.verifyFile(self.rootDir + '/dummy/aaa_first')
        self.verifyFile(self.rootDir + '/dummy/file')
        self.verifyFile(self.rootDir + '/dummy/zzz_last')
        rc, str = self.captureOutput(self.erasePkg,
            self.rootDir, 'failpreun:rpm=1.0-1-1')
        self.assertEquals(str,
            'error: %preun(failpreun-1.0-1.noarch) scriptlet failed, exit status 127\n')
        self.verifyNoFile(self.rootDir + '/dummy/file')

    @conary_test.rpm
    def testNonRootUnpackFailures(self):
        'test what happens when RPM unpack fails as non-root'
        # CNY-3462
        f = self.addRPMComponent('aaa_first:rpm=1.0-1-1',
                                 'aaa_first-1.0-1.noarch.rpm')
        f = self.addRPMComponent('dev:rpm=1.0-1-1',
                                 'dev-1.0-1.noarch.rpm')
        rc, str = self.captureOutput(self.updatePkg,
                       ['aaa_first:rpm=1.0-1-1',
                        'dev:rpm=1.0-1-1'])
        warning = str.strip().split('\n')[-1]
        self.assertEquals(warning,
                          'warning: RPM failed to unpack dev-1.0-1.noarch')
        self.verifyFile(self.rootDir + '/dummy/aaa_first')

    @conary_test.rpm
    def testDuplicateRpms(self):
        # CNY-3470
        v1 = self.addRPMComponent("simple:rpm=1.0-1", 'simple-1.0-1.i386.rpm')
        v2 = self.addRPMComponent("simple:rpm=1.0-2", 'simple-1.0-1.i386.rpm')

        self.updatePkg('simple:rpm=1.0-1')
        self.updatePkg('simple:rpm=1.0-2', keepExisting = True)
        self.erasePkg(self.rootDir, 'simple:rpm=1.0-1')
        self.erasePkg(self.rootDir, 'simple:rpm=1.0-2')

        self.updatePkg('simple:rpm=1.0-1')
        self.updatePkg('simple:rpm=1.0-2', keepExisting = True)
        self.erasePkg(self.rootDir, [ 'simple:rpm=1.0-1', 'simple:rpm=1.0-2' ])

        self.updatePkg('simple:rpm=1.0-1')
        self.updatePkg('simple:rpm=1.0-2')
        self.erasePkg(self.rootDir, 'simple:rpm=1.0-2')

    @conary_test.rpm
    def testNetSharedPath(self):
        # CNY-3503
        p = self.addRPMComponent('netshared:rpm=1.0-1',
                                 'netshared-1.0-1.noarch.rpm')

        util.mkdirChain(self.cfg.root + '/etc/rpm/')
        #self.updatePkg('netshared:rpm=1.0-1')
        #self.verifyFile(self.rootDir + '/local/shouldexist')
        ##self.verifyFile(self.rootDir + '/excluded/shouldnotexist')

        self.resetRoot()
        util.mkdirChain(self.cfg.root + '/etc/rpm/')
        util.mkdirChain(self.cfg.root + '/excluded')
        self.writeFile(self.cfg.root + '/excluded/shouldnotexist', 'unmanaged')

        # inside the method to let @conary_test.rpm keep the import conditional
        import rpm
        rpm.addMacro('_netsharedpath', '/excluded:/usr/local')
        try:
            self.updatePkg('netshared:rpm=1.0-1')
        finally:
            rpm.delMacro('_netsharedpath')

        self.verifyFile(self.rootDir + '/local/shouldexist')
        self.verifyFile(self.rootDir + '/excluded/shouldnotexist', 'unmanaged')

        self.erasePkg(self.rootDir, 'netshared:rpm')

    @conary_test.rpm
    def testFileOverrides(self):
        # CNY-3586; CNY-3590
        # Unfortunately we can't use addRPMComponent, we need the policy to
        # mark files as being overwritten
        recipe = r"""
class TestPackage(CapsuleRecipe):
    name = 'with-config-special'
    version = '0.1'

    clearBuildReqs()
    def setup(r):
        r.addCapsule('with-config-special-0.3-1.noarch.rpm')
        r.Create('/usr/share/with-config-special.txt',
            contents='some other content\n', mode=0755)
        r.Create('/usr/share/new-content.txt',
            contents='some new content\n', mode=0644)
"""
        pkgname = 'with-config-special'
        self.makeSourceTrove(pkgname, recipe)
        built = self.cookFromRepository(pkgname)
        nvf = built[0]

        self.updatePkg('%s=0.1-1-1' % pkgname)
        self.verifyFile(self.rootDir + '/usr/share/with-config-special.txt',
            'Some extra data\n', perms=0644)
        # File additions should be honored
        self.verifyFile(self.rootDir + '/usr/share/new-content.txt',
            'some new content\n', perms=0644)

    @conary_test.rpm
    def testFileModeChanges(self):
        # CNY-3590
        # Unfortunately we can't use addRPMComponent, we need the policy to
        # mark files as being overwritten
        recipe = r"""
class TestPackage(CapsuleRecipe):
    name = 'with-config-special'
    version = '0.1'

    clearBuildReqs()
    def setup(r):
        r.addCapsule('with-config-special-0.3-1.noarch.rpm')
        r.SetModes('/usr/share/with-config-special.txt', 0755)
"""
        pkgname = 'with-config-special'
        self.makeSourceTrove(pkgname, recipe)
        built = self.cookFromRepository(pkgname)
        nvf = built[0]

        self.updatePkg('%s=0.1-1-1' % pkgname)
        # Make sure we DO NOT change the mode here (see CNY-3590)
        self.verifyFile(self.rootDir + '/usr/share/with-config-special.txt',
            'Some extra data\n', perms=0644)

    @conary_test.rpm
    def testUnchangedRPM(self):
        cmp1 = self.addRPMComponent("simple:rpm=1.0-1-1",
                                    'simple-1.0-1.i386.rpm')
        self.updatePkg('simple:rpm')
        cmp1 = self.addRPMComponent("simple:rpm=1.0-1-2",
                                    'simple-1.0-1.i386.rpm')
        self.updatePkg('simple:rpm')

    @conary_test.rpm
    @testhelp.context('rollback')
    def testFileTypeChange(self):
        self.addRPMComponent("file-type-change:rpm=1-1-1",
                             'file-type-change-1-1.i386.rpm')
        self.addRPMComponent("file-type-change:rpm=2-1-1",
                             'file-type-change-2-1.i386.rpm')
        self.updatePkg('file-type-change:rpm=1')
        self.assertEquals(os.readlink(self.rootDir + '/test'), 'foo')
        self.updatePkg('file-type-change:rpm=2')
        self.verifyFile(self.rootDir + '/test', '')
        self.rollback(1)
        self.assertEquals(os.readlink(self.rootDir + '/test'), 'foo')

    @conary_test.rpm
    def testChangingSharedUpdateRPM(self):
        'CNY-3620'
        if 'x86_64' not in str(self.cfg.buildFlavor):
            raise testhelp.SkipTestException('Skip test on x86 arch')
        # avoid needing to flavor using names
        su1032 = self.addRPMComponent('shared-update-32:rpm=1.0',
                                      'shared-update-1.0-1.i386.rpm')
        su1064 = self.addRPMComponent('shared-update-64:rpm=1.0',
                                      'shared-update-1.0-1.x86_64.rpm')
        su1132 = self.addRPMComponent('shared-update-32:rpm=1.1',
                                      'shared-update-1.1-1.i386.rpm',
                                      versus=su1032)
        su1164 = self.addRPMComponent('shared-update-64:rpm=1.1',
                                      'shared-update-1.1-1.x86_64.rpm',
                                      versus=su1064)
        self.updatePkg(['shared-update-32:rpm=1.0', 'shared-update-64:rpm=1.0'])
        self.verifyFile(self.rootDir + '/usr/share/test', 'contents1.0\n')
        self.updatePkg(['shared-update-32:rpm=1.1', 'shared-update-64:rpm=1.1'])
        self.verifyFile(self.rootDir + '/usr/share/test', 'contents1.1\n')

    @conary_test.rpm
    def testRPMJobOrdering(self):
        """
        Ensure that introducing a native conary package in the dependency chain
        between two encapsuled RPM packages causes Conary to split the three
        packages into separate jobs.

        foo:rpm -> bar:runtime -> baz:rpm
        """

        self.addRPMComponent('baz:rpm=1.0', 'simple-1.0-1.i386.rpm')
        self.addComponent('bar:runtime=1.0',
            requires=deps.parseDep('trove: baz:rpm'))
        self.addRPMComponent('foo:rpm=1.0', 'ownerships-1.0-1.i386.rpm',
            requires=deps.parseDep('trove: bar:runtime'))

        rc, txt = self.captureOutput(self.updatePkg,
            [ 'foo:rpm', ], resolve=True, raiseError=True, info=True)

        self.assertEquals(txt, 'Job 1 of 3:\n'
                               '    Install baz:rpm=1.0-1-1\n'
                               'Job 2 of 3:\n'
                               '    Install bar:runtime=1.0-1-1\n'
                               'Job 3 of 3:\n'
                               '    Install foo:rpm=1.0-1-1\n')

    @conary_test.rpm
    @testhelp.context('rollback')
    def testCapsuleLocalRollbacks(self):
        try:
            self.cfg.localRollbacks = True
            c = self.addRPMComponent("simple:rpm=1.0", 'simple-1.0-1.i386.rpm')
            csPath = self.workDir + '/simple.ccs'
            repos = self.getRepositoryClient()
            repos.createChangeSetFile([
                (c.getName(), ( None, None ),
                              ( c.getVersion(), c.getFlavor() ), True ) ]
                                      , csPath)
            file("/tmp/foo", "w").write(c.freeze())
            self.addRPMComponent("simple:rpm=1.1", 'simple-1.1-1.i386.rpm')
            self.updatePkg('simple:rpm=1.0')

            testPath = os.path.join(self.rootDir, 'normal')
            self.verifyFile(testPath, 'normal\n')
            f = file(testPath, "w")
            f.write("rollback check")

            self.updatePkg('simple:rpm=1.1')
            self.verifyFile(testPath, 'changed-normal\n')

            e = self.assertRaises(errors.MissingRollbackCapsule,
                                  self.rollback, 1)
            assert('simple-1.0-1.i386.rpm' in str(e))
            self.rollback(1, capsuleChangesets = [ csPath ] )
            f.write("rollback check")

            self.updatePkg('simple:rpm=1.1')
            self.verifyFile(testPath, 'changed-normal\n')
            self.writeFile(self.workDir + '/other', 'some file')
            self.rollback(1, capsuleChangesets = [ self.workDir ] )
            f.write("rollback check")

            self.erasePkg(self.rootDir, 'simple:rpm')
            self.rollback(1, capsuleChangesets = [ self.workDir ] )
        finally:
            self.cfg.localRollbacks = False

    def checkMd5(self, path, md5):
        d = md5String(open(self.rootDir + path).read())
        self.assertEquals(md5ToString(d), md5)

    def owners(self, path):
        db = self.openDatabase()
        return set( x[0:3] for x in db.iterFindPathReferences(
                                            path, justPresent = True) )

    def checkOrdering(self, troves):
        lastOrder = [x[22:].strip() for x in
                     file(self.rootDir + '/var/log/conary').readlines()
                     if 'RPM install order' in x][-1]
        self.assertEquals(lastOrder.split(': ', 1)[1], troves)

    def checkOwners(self, path, troves):
        assert(self.owners(path) ==
                set( x.getNameVersionFlavor() for x in troves ))

    @conary_test.rpm
    def testEncapToNative(self):
        """
        Update from encapsulated package to native package with the same
        contents and modes, ensure that the file does not disappear.

        @tests: CNY-3762
        """
        self.addRPMComponent('foo:rpm=1.0', 'simple-1.0-1.i386.rpm')
        self.updatePkg('foo:rpm', raiseError=True)

        recipe = r"""
class TestPackage(CapsuleRecipe):
    name = 'foo'
    version = '2.0'

    clearBuildReqs()
    def setup(r):
        r.addArchive('simple-1.0-1.i386.rpm', dir='/', preserveOwnership=True)
"""
        src = self.makeSourceTrove('foo', recipe)
        self.cookFromRepository('foo')[0]
        self.updatePkg(['-foo:rpm', 'foo:runtime'], depCheck=False,
                raiseError=True)
        path = os.path.join(self.rootDir, 'normal')
        self.assertEqual(os.stat(path).st_size, 7)

    @conary_test.rpm
    def testEncapToNativeSloppy(self):
        """
        Update from encapsulated package to native package with the same
        contents but different modes, ensure that the file does not disappear.

        @tests: CNY-3762
        """
        self.addRPMComponent('foo:rpm=1.0', 'simple-1.0-1.i386.rpm')
        self.updatePkg('foo:rpm', raiseError=True)

        recipe = r"""
class TestPackage(CapsuleRecipe):
    name = 'foo'
    version = '2.0'

    clearBuildReqs()
    def setup(r):
        r.addArchive('simple-1.0-1.i386.rpm', dir='/')
        r.Ownership('nobody', 'nobody', '.*')
        r.SetModes('/dir', 0700)
        r.SetModes('/normal', 0600)
"""
        src = self.makeSourceTrove('foo', recipe)
        self.cookFromRepository('foo')[0]
        self.updatePkg(['-foo:rpm', 'foo:runtime'], depCheck=False,
                raiseError=True)
        path = os.path.join(self.rootDir, 'normal')
        self.assertEqual(os.stat(path).st_size, 7)
        self.assertEqual(oct(os.stat(path).st_mode), '0100600')
        path = os.path.join(self.rootDir, 'dir')
        self.assertEqual(oct(os.stat(path).st_mode), '040700')

    @conary_test.rpm
    def testEncapToNativeChanged(self):
        """
        Update from encapsulated to native package with some different contents

        @tests: CNY-3762
        """
        # Intentionally put a trailing slash on the root dir to tickle bugs
        # where a path not created with joinPaths() might cause mismatches. Of
        # course the most common real-world case, root = '/', has a "trailing"
        # slash, whereas usually in the testsuite a chroot is used and no
        # trailing slash is present.
        self.rootDir += '/'

        self.addRPMComponent('foo:rpm=1.0', 'simple-1.0-1.i386.rpm')
        self.updatePkg('foo:rpm', raiseError=True)

        recipe = r"""
class TestPackage(CapsuleRecipe):
    name = 'foo'
    version = '2.0'

    clearBuildReqs()
    def setup(r):
        r.addArchive('simple-1.0-1.i386.rpm', dir='/')
        r.Ownership('nobody', 'nobody', '.*')
        r.SetModes('/dir', 0700)
        r.Create('/normal', contents='different stuff\n', mode=0600)
"""
        src = self.makeSourceTrove('foo', recipe)
        self.cookFromRepository('foo')[0]
        self.updatePkg(['-foo:rpm', 'foo:runtime'], depCheck=False,
                raiseError=True)
        path = os.path.join(self.rootDir, 'normal')
        self.assertEqual(os.stat(path).st_size, 16)
        self.assertEqual(oct(os.stat(path).st_mode), '0100600')
        path = os.path.join(self.rootDir, 'dir')
        self.assertEqual(oct(os.stat(path).st_mode), '040700')

    @conary_test.rpm
    def testUsrmoveUpdate(self):
        """
        Update file from /sbin to /usr/sbin while /sbin is a symlink

        @tests: CNY-3885
        """
        os.makedirs(os.path.join(self.rootDir, 'usr/sbin'))
        os.symlink('usr/sbin', os.path.join(self.rootDir, 'sbin'))
        self.addRPMComponent('usrmove:rpm=1.0', 'usrmove-1.0-1.x86_64.rpm')
        self.updatePkg('usrmove:rpm', raiseError=True)
        self.addRPMComponent('usrmove:rpm=2.0', 'usrmove-2.0-1.x86_64.rpm')
        self.updatePkg('usrmove:rpm', raiseError=True)
        self.assertEqual(open(os.path.join(self.rootDir, 'usr/sbin/usrmove')).read(), '2.0\n')
コード例 #19
0
ファイル: streams.py プロジェクト: fedora-conary/conary
 def setFromString(self, hexdigest):
     StringStream.set(self, sha1helper.sha1FromString(hexdigest))
コード例 #20
0
class TroveStoreTest(dbstoretest.DBStoreTestBase):

    id1 = md5FromString("00010001000100010001000100010001")
    id2 = md5FromString("00010001000100010001000100010002")
    id3 = md5FromString("00010001000100010001000100010003")
    id4 = md5FromString("00010001000100010001000100010004")
    id5 = md5FromString("00010001000100010001000100010005")

    fid1 = sha1FromString("1001000100010001000100010001000100010001")
    fid2 = sha1FromString("1001000100010001000100010001000100010002")
    fid3 = sha1FromString("1001000100010001000100010001000100010003")
    fid4 = sha1FromString("1001000100010001000100010001000100010004")
    fid5 = sha1FromString("1001000100010001000100010001000100010005")

    def _connect(self):
        db = self.getDB()
        schema.createSchema(db)
        schema.setupTempTables(db)
        depSchema.setupTempDepTables(db)
        store = trovestore.TroveStore(db)
        auth = netauth.NetworkAuthorization(db, ['localhost'])
        auth.addUser('anonymous', 'anonymous')
        auth.addRole('anonymous')
        auth.addRoleMember('anonymous', 'anonymous')
        auth.addAcl('anonymous', None, None, write=False, remove=False)
        auth.setAdmin('anonymous', False)
        return store

    def testTroves(self, flavor=None):
        if flavor is None:
            flavor = deps.Flavor()

        store = self._connect()

        dirSet = set(['/etc', '/bin'])
        baseSet = set(
            ['passwd', 'services', 'group', '1', '2', '3', 'distributed'])

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")

        branch = v10.branch()
        store.createTroveBranch("testtrove", branch)

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)
        f2 = files.FileFromFilesystem("/etc/services", self.id2)
        f3 = files.FileFromFilesystem("/etc/group", self.id3)
        # make a really huge dependency, thus a very large file stream
        req = deps.DependencySet()
        for x in xrange(10000):
            req.addDep(deps.SonameDependencies,
                       deps.Dependency("libtest.so.%d" % x))
        f3.requires.set(req)
        # make sure it's way too big for a blob in mysql
        assert (len(f3.freeze()) >= 50000)

        cl = changelog.ChangeLog(
            "test", "*****@*****.**", """\
Some changes are good.
Some changes are bad.
Some changes just are.
""")

        trv = trove.Trove('testcomp', v10, flavor, cl)
        trv.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())
        trv.addFile(f2.pathId(), "/bin/2", v10, f2.fileId())
        trv.addFile(f3.pathId(), "/bin/3", v10, f3.fileId())
        trv.addFile(self.id4, "/bin/distributed", v10, self.fid4)
        trv.troveInfo.size.set(1234)
        trv.troveInfo.sourceName.set('somesource')

        req = deps.DependencySet()
        req.addDep(deps.FileDependencies, deps.Dependency("/bin/bash"))
        req.addDep(deps.TroveDependencies, deps.Dependency("foo:runtime"))
        req.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setRequires(req)

        # this also lets us peek at the database to make sure libtest.so.1
        # is only in the dep table once
        prv = deps.DependencySet()
        prv.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setProvides(prv)
        trv.computeDigests()

        store.db.transaction()
        store.addTroveSetStart([], dirSet, baseSet)
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          f1.fileId(),
                          v10,
                          fileStream=f1.freeze())
        troveInfo.addFile(f2.pathId(),
                          "/bin/2",
                          f2.fileId(),
                          v10,
                          fileStream=f2.freeze())
        troveInfo.addFile(f3.pathId(),
                          "/bin/3",
                          f3.fileId(),
                          v10,
                          fileStream=f3.freeze())
        troveInfo.addFile(self.id4, "/bin/distributed", self.fid4, v10)
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        store.db.commit()

        cu = store.db.cursor()
        cu.execute("SELECT count(*) FROM Dependencies WHERE "
                   "name = 'libtest.so.1'")
        self.assertEqual(cu.next(), (1, ))

        # make sure the sha1s were stored
        cu.execute("""
        SELECT dirname, basename, sha1
        FROM TroveFiles
        JOIN FileStreams USING (streamId)
        JOIN FilePaths ON TroveFiles.filePathId = FilePaths.filePathId
        JOIN Dirnames ON FilePaths.dirnameId = Dirnames.dirnameId
        JOIN Basenames ON FilePaths.basenameId = Basenames.basenameId
        ORDER BY dirname,basename""")
        items = [(os.path.join(cu.frombinary(x[0]),
                               cu.frombinary(x[1])), cu.frombinary(x[2]))
                 for x in cu.fetchall()]
        self.assertEqual(items, [("/bin/1", f1.contents.sha1()),
                                 ("/bin/2", f2.contents.sha1()),
                                 ("/bin/3", f3.contents.sha1()),
                                 ("/bin/distributed", None)])

        cl = changelog.ChangeLog("test", "*****@*****.**", "another log\n")

        fromRepos = store.getTrove("testcomp", v10, flavor, cl)
        self.assertEqual(fromRepos, trv)
        self.assertEqual(fromRepos.getVersion().timeStamps(),
                         trv.getVersion().timeStamps())
        self.assertEqual(fromRepos.getChangeLog(), trv.getChangeLog())

        self.assertEqual([
            x for x in store.getTrove("testcomp", v10, flavor,
                                      withFiles=False).iterFileList()
        ], [])

        l = store.iterFilesInTrove("testcomp", v10, flavor, sortByPath=True)
        l = [x for x in l]
        self.assertEqual(l, [(f1.pathId(), "/bin/1", f1.fileId(), v10),
                             (f2.pathId(), "/bin/2", f2.fileId(), v10),
                             (f3.pathId(), "/bin/3", f3.fileId(), v10),
                             (self.id4, "/bin/distributed", self.fid4, v10)])

        cl = changelog.ChangeLog("test", "*****@*****.**", "log for testpkg\n")
        trv2 = trove.Trove("testpkg", v10, flavor, cl)
        trv2.addTrove(trv.getName(), v10, flavor)
        trv2.addTrove("weakref", v10, flavor, weakRef=True)
        trv2.computeDigests()
        store.addTroveSetStart([], dirSet, baseSet)
        troveInfo = store.addTrove(trv2, trv2.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        self.assertEqual(store.getTrove("testpkg", v10, flavor), trv2)

        self.assertEqual([
            x for x in store.iterTroves([("testcomp", v10,
                                          flavor), ("testpkg", v10, flavor)])
        ], [trv, trv2])
        self.assertEqual([
            x for x in store.iterTroves([("testpkg", v10,
                                          flavor), ("testcomp", v10, flavor)])
        ], [trv2, trv])
        self.assertEqual([
            x for x in store.iterTroves([("testpkg", v10,
                                          flavor), ("testpkg", v10, flavor)])
        ], [trv2, trv2])
        self.assertEqual([
            x for x in store.iterTroves([("testpkg", v10,
                                          flavor), ("blah", v10, flavor)])
        ], [trv2, None])
        self.assertEqual([
            x for x in store.iterTroves([("blah", v10,
                                          flavor), ("testpkg", v10, flavor)])
        ], [None, trv2])
        self.assertEqual(
            [x for x in store.iterTroves([("blah", v10, flavor)])], [None])
        self.assertEqual([
            x for x in store.iterTroves([(
                "testcomp", v10, flavor), ("blah", v10,
                                           flavor), ("testpkg", v10, flavor)])
        ], [trv, None, trv2])

        # erasing doesn't work
        #store.eraseTrove("testcomp", v10, None)
        #store.commit()
        self.assertEqual(store.getTrove("testpkg", v10, flavor), trv2)

        map = {'testpkg': [v10]}
        flavors = store.getTroveFlavors(map)
        if flavor is not None:
            flavorStr = flavor.freeze()
        else:
            flavorStr = ''
        self.assertEqual(flavors, {'testpkg': {v10: [flavorStr]}})

        map = {'testpkg3': [v10]}
        flavors = store.getTroveFlavors(map)
        self.assertEqual(flavors, {'testpkg3': {v10: []}})

        # test getFiles
        fileObjs = store.getFiles([(f1.pathId(), f1.fileId()),
                                   (f2.pathId(), f2.fileId())])
        self.assertEqual(fileObjs[(f1.pathId(), f1.fileId())], f1)
        self.assertEqual(fileObjs[(f2.pathId(), f2.fileId())], f2)

        # test that asking for an invalid fileid/pathid pair results
        # in no entry for the (pathid, fileid) in the returned dict
        invalidPathId = md5FromString('9' * 32)
        invalidFileId = sha1FromString('9' * 40)
        fileObjs = store.getFiles([(invalidPathId, invalidFileId)])
        # make sure fileObjs is empty
        assert (not fileObjs)

        # test that asking for contents that have to come from
        # a different repository works - we should get None
        # back
        fileObjs = store.getFiles([(self.id4, self.fid4)])
        self.assertEqual(fileObjs, {(self.id4, self.fid4): None})

    def testMetadata(self):
        store = self._connect()
        emptyFlavor = deps.Flavor()
        v1 = ThawVersion("/conary.rpath.com@test:trunk/1:1-1")
        branch = v1.branch()
        store.createTroveBranch("testtrove", branch)

        md_v1_l = {
            "shortDesc": "Short Desc",
            "longDesc": "Long Desc",
            "url": ["url1", "url2"],
            "license": ["CPL", "GPL"],
            "category": ["cat1", "cat2"],
            "version": "/conary.rpath.com@test:trunk/1-1",
            "source": "local",
            "language": "C",
        }
        md_v1_fr_l = {
            "shortDesc": "French Short Desc",
            "longDesc": "French Long Desc",
            "url": ["url1", "url2"],
            "license": ["CPL", "GPL"],
            "category": ["cat1", "cat2"],
            "version": "/conary.rpath.com@test:trunk/1-1",
            "source": "local",
            "language": "fr",
        }
        md_v2_l = {
            "shortDesc": "Short Desc V2",
            "longDesc": "Long Desc V2",
            "url": ["url1v2"],
            "license": ["CPLv2", "GPLv2"],
            "category": ['cat1v2', 'cat2v2', 'cat3v2'],
            "version": "/conary.rpath.com@test:trunk/1-2",
            "source": "foo",
            "language": "C",
        }

        trv3 = trove.Trove("testpkg3", v1, emptyFlavor, None)
        branch = v1.branch()

        store.db.transaction()

        store.updateMetadata("testpkg3",
                             branch,
                             "Short Desc",
                             "Long Desc",
                             urls=['url1', 'url2'],
                             categories=['cat1', 'cat2'],
                             licenses=['GPL', 'CPL'],
                             source="",
                             language="C")

        store.updateMetadata("testpkg3", branch, "French Short Desc",
                             "French Long Desc", [], [], [], "", "fr")

        store.db.commit()

        md_v1 = store.getMetadata("testpkg3", branch)
        md_v1_fr = store.getMetadata("testpkg3", branch, language="fr")

        self.assertEqual(md_v1.freeze(), md_v1_l)
        self.assertEqual(md_v1_fr.freeze(), md_v1_fr_l)

        v2 = ThawVersion("/conary.rpath.com@test:trunk/1:1-2")

        store.db.transaction()

        store.updateMetadata("testpkg3",
                             branch,
                             "Short Desc V2",
                             "Long Desc V2",
                             urls=['url1v2'],
                             categories=['cat1v2', 'cat2v2', 'cat3v2'],
                             licenses=['CPLv2', 'GPLv2'],
                             source="foo",
                             language="C")

        store.db.commit()

        md_v2 = store.getMetadata("testpkg3", branch)
        md_v1 = store.getMetadata("testpkg3", branch, version=v1)
        md_v1_fr = store.getMetadata("testpkg3",
                                     branch,
                                     version=v1,
                                     language="fr")

        self.assertEqual(md_v2.freeze(), md_v2_l)
        self.assertEqual(md_v1.freeze(), md_v1_l)
        self.assertEqual(md_v1_fr.freeze(), md_v1_fr_l)

    def testTroveFlavor(self):
        flavor = deps.Flavor()
        flavor.addDep(
            deps.UseDependency,
            deps.Dependency('use', [('foo', deps.FLAG_SENSE_REQUIRED)]))
        self.testTroves(flavor=flavor)

    def testTroveMultiFlavor(self):
        # create a package with 3 components, each use a different use
        # flag.  add the package before the components.  the goal is
        # to make the trovestore create more than one flavor
        flags = ('foo', 'bar', 'baz')
        flavors = []
        for flag in flags:
            flavor = deps.Flavor()
            flavor.addDep(
                deps.UseDependency,
                deps.Dependency('use', [(flag, deps.FLAG_SENSE_REQUIRED)]))
            flavor.addDep(deps.InstructionSetDependency,
                          deps.Dependency('x86', []))
            flavors.append(flavor)

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")
        store = self._connect()

        # create components to add to the package
        troves = []
        for flag, flavor in zip(flags, flavors):
            trv = trove.Trove('test:%s' % flag, v10, flavor, None)
            trv.computeDigests()
            troves.append(trv)

        # add the package
        union = deps.Flavor()
        for flavor in flavors:
            union.union(flavor)
        trv2 = trove.Trove("test", v10, union, None)
        for trv in troves:
            trv2.addTrove(trv.getName(), v10, trv2.getFlavor())
        trv2.computeDigests()
        store.addTroveSetStart([], [], [])
        troveInfo = store.addTrove(trv2, trv2.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()

        # add the troves
        store.addTroveSetStart([], [], [])
        for trv in troves:
            troveInfo = store.addTrove(trv, trv.diff(None)[0])
            store.addTroveDone(troveInfo)
        store.addTroveSetDone()

        for trv in troves:
            self.assertEqual(
                trv,
                store.getTrove(trv.getName(), trv.getVersion(),
                               trv.getFlavor()))

        troveFlavors = store.getTroveFlavors({'test': [v10]})
        self.assertEqual(troveFlavors['test'][v10], [union.freeze()])

    def testRemoved(self):
        store = self._connect()

        old = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-3")
        x86 = deps.parseFlavor("is:x86")

        removed = trove.Trove("trvname",
                              old,
                              x86,
                              None,
                              type=trove.TROVE_TYPE_REMOVED)
        removed.computeDigests()

        store.addTroveSetStart([], [], [])
        troveInfo = store.addTrove(removed, removed.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()

        assert (store.getTrove("trvname", old, x86) == removed)

    def testRedirect(self):
        store = self._connect()

        old = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-3")
        x86 = deps.parseFlavor("is:x86")
        x86_64 = deps.parseFlavor("is:x86_64")

        redir = trove.Trove("trvname",
                            old,
                            x86,
                            None,
                            type=trove.TROVE_TYPE_REDIRECT)
        redir.addRedirect("trv1", old.branch(), x86)
        redir.addRedirect("trv2", old.branch(), x86_64)
        redir.computeDigests()

        store.addTroveSetStart([], [], [])
        troveInfo = store.addTrove(redir, redir.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()

        assert (store.getTrove("trvname", old, x86) == redir)

    def testBrokenPackage(self):
        store = self._connect()

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")
        v20 = ThawVersion("/conary.rpath.com@test:trunk/20:1.2-20")
        flavor = deps.Flavor()
        flavor2 = deps.parseFlavor('is:x86')

        trv = trove.Trove("testpkg", v10, flavor, None)
        trv.addTrove("testpkg:runtime", v20, flavor)
        trv.computeDigests()

        store.addTroveSetStart([], [], [])
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        self.assertRaises(AssertionError, store.addTroveDone, troveInfo)

        store.rollback()

        trv = trove.Trove("testpkg", v10, flavor, None)
        trv.addTrove("testpkg:runtime", v10, flavor2)
        trv.computeDigests()
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        self.assertRaises(AssertionError, store.addTroveDone, troveInfo)

    @testhelp.context('performance')
    def testMassiveIterTroves(self):
        store = self._connect()

        infoList = []
        expected = []
        f = deps.parseFlavor('is:x86')
        v = ThawVersion('/conary.rpath.com@test:trunk/10:1-1')
        # add 2000 test components
        store.addTroveSetStart([], [], [])
        for x in xrange(500):
            n = 'test%d:runtime' % x
            t = trove.Trove(n, v, f, None)
            t.computeDigests()
            troveInfo = store.addTrove(t, t.diff(None)[0])
            store.addTroveDone(troveInfo)
            # we want to iterTroves for each of our components (which
            # ends up being a no-op)
            infoList.append((n, v, f))
            expected.append(t)
        store.addTroveSetDone()
        start = time.time()
        result = [x for x in store.iterTroves(infoList)]
        end = time.time()

        # make sure we got the expected results
        assert (result == expected)
        # we should be able to iter through all of these troves in
        # well under one seconds
        if end - start > 5:
            sys.stderr.write("\nWarning: testMassiveIterTroves: test ran in "
                             "%.3f seconds, expected < 5\n\n" % (end - start))

    def testDuplicateStreams(self):
        store = self._connect()
        flavor = deps.Flavor()

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")
        v20 = ThawVersion("/conary.rpath.com@test:trunk/20:1.2-20")

        dirNames = set(['/bin', '/etc'])
        baseNames = set(['1', '2'])

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)

        trv = trove.Trove("testpkg:runtime", v10, flavor, None)
        trv.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())
        trv.computeDigests()

        store.db.transaction()
        store.addTroveSetStart([], dirNames, baseNames)
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        troveInfo.addFile(f1.pathId(), "/bin/1", f1.fileId(), v10)
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        store.db.commit()

        trv = trove.Trove("testpkg:runtime", v20, flavor, None)
        trv.addFile(f1.pathId(), "/bin/1", v20, f1.fileId())
        trv.addFile(f1.pathId(), "/bin/2", v20, f1.fileId())
        trv.computeDigests()

        store.db.transaction()
        store.addTroveSetStart([], dirNames, baseNames)
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        troveInfo.addFile(f1.pathId(), "/bin/1", f1.fileId(), v10)
        troveInfo.addFile(f1.pathId(), "/bin/2", f1.fileId(), v10)
        store.addTroveDone(troveInfo)
        store.db.commit()

    def testRemoval(self):
        threshold = 60 * 5
        # 5 minutes

        def _dbStatus(db):
            stat = {}
            cu = db.cursor()

            for table in db.tables:
                cu.execute("SELECT * FROM %s" % table)
                l = cu.fetchall()
                # throw away anything which looks a timestamp; this will
                # break if the test case takes more than 5 minutes to run
                stat[table] = set()
                for row in l:
                    thisRow = []
                    for item in row:
                        if not isinstance(item, (float, decimal.Decimal)) or \
                                    abs(item - now) > threshold:
                            thisRow.append(item)

                    stat[table].add(tuple(thisRow))

            return stat

        def _checkStateDiff(one, two):
            if one != two:
                assert (one.keys() == two.keys())
                for key in one:
                    if one[key] != two[key]:
                        print "table %s has changed" % key
                raise AssertionError, "\n%s\n!=\n%s" % (one, two)

        store = self._connect()

        # get the current timestamp from the database
        cu = store.db.cursor()
        cu.execute('''create table timestamp(
                      foo     INTEGER,
                      changed NUMERIC(14,0) NOT NULL DEFAULT 0)''')
        store.db.loadSchema()
        store.db.createTrigger('timestamp', 'changed', "INSERT")
        cu.execute('insert into timestamp values(0, 0)')
        cu.execute('select changed from timestamp')
        now = cu.fetchall()[0][0]

        emptyState = _dbStatus(store.db)

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")
        v20 = ThawVersion("/conary.rpath.com@test:trunk/20:1.2-20")
        vB = ThawVersion("/conary.rpath.com@test:branch/1:0-0")
        vOtherRepo = ThawVersion("/other.repos.com@some:label/1:0-0")
        branch = v10.branch()

        flavor = deps.parseFlavor('is:x86')
        flavor64 = deps.parseFlavor('is:x86_64')

        store.createTroveBranch("trv:comp", branch)

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)
        f2 = files.FileFromFilesystem("/etc/services", self.id2)
        # add a file that has no contents sha1
        try:
            d = tempfile.mkdtemp()
            os.symlink('foo', d + '/foo')
            f5 = files.FileFromFilesystem(d + '/foo', self.id5)
        finally:
            shutil.rmtree(d)

        req = deps.parseDep("file: /bin/bash file: /bin/awk")

        dirNames = set(['/bin', ''])
        baseNames = set(['1', '2', 'distributed', 'foo', 'group-foo.recipe'])

        cl = changelog.ChangeLog("test", "*****@*****.**", "changelog\n")

        trv = trove.Trove('trv:comp', v10, flavor, cl)
        trv.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())
        trv.addFile(f2.pathId(), "/bin/2", v10, f2.fileId())
        trv.addFile(self.id4, "/bin/distributed", v10, self.fid4)
        trv.addFile(f5.pathId(), "/bin/foo", v10, f5.fileId())
        trv.troveInfo.size.set(1234)
        trv.setRequires(req)

        store.db.transaction()
        store.addTroveSetStart([], dirNames, baseNames)
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          f1.fileId(),
                          v10,
                          fileStream=f1.freeze())
        troveInfo.addFile(f2.pathId(),
                          "/bin/2",
                          f2.fileId(),
                          v10,
                          fileStream=f2.freeze())
        troveInfo.addFile(f5.pathId(),
                          "/bin/foo",
                          f5.fileId(),
                          v10,
                          fileStream=f5.freeze())
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        store.db.commit()
        oneTroveState = _dbStatus(store.db)

        rc = store._removeTrove("trv:comp", v10, flavor)
        self.assertEqual(set(rc), set([f1.contents.sha1(),
                                       f2.contents.sha1()]))
        state = _dbStatus(store.db)
        _checkStateDiff(state, emptyState)
        store.db.rollback()

        # the redir itself doesn't overlap with trv:comp; this makes sure
        # that the tables which the redir target needs are preserved
        redir = trove.Trove('redir:comp',
                            vB,
                            flavor64,
                            cl,
                            type=trove.TROVE_TYPE_REDIRECT)
        redir.addRedirect('trv:comp', v10.branch(), flavor)
        store.addTroveSetStart([], dirNames, baseNames)
        troveInfo = store.addTrove(redir, redir.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        rc = store._removeTrove("trv:comp", v10, flavor)
        redir2 = store.getTrove('redir:comp', vB, flavor64)
        assert (redir == redir2)
        rc = store._removeTrove("redir:comp", vB, flavor64)
        state = _dbStatus(store.db)
        _checkStateDiff(state, emptyState)

        store.db.rollback()

        trv2 = trv.copy()
        trv2.changeVersion(v20)

        store.db.transaction()
        store.addTroveSetStart([], dirNames, baseNames)
        troveInfo = store.addTrove(trv2, trv2.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          f1.fileId(),
                          v10,
                          fileStream=f1.freeze())
        troveInfo.addFile(f2.pathId(),
                          "/bin/2",
                          f2.fileId(),
                          v10,
                          fileStream=f2.freeze())
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        store.db.commit()
        twoTroveState = _dbStatus(store.db)

        rc = store._removeTrove("trv:comp", v20, flavor)
        assert (not rc)
        state = _dbStatus(store.db)
        _checkStateDiff(state, oneTroveState)
        rc = store._removeTrove("trv:comp", v10, flavor)
        assert (set(rc) == set([f1.contents.sha1(), f2.contents.sha1()]))
        state = _dbStatus(store.db)
        _checkStateDiff(state, emptyState)

        store.db.rollback()

        # add a trove which shares a file with trv:comp and make sure removing
        # it doesn't remove the sha1s (make sure the fileIds are different)
        anotherTrove = trove.Trove('another:comp', v10, flavor, cl)
        anotherF = f1.copy()
        anotherF.inode.owner.set('unowned')
        anotherTrove.addFile(f1.pathId(), "/bin/1", v10, anotherF.fileId())
        store.addTroveSetStart([], dirNames, baseNames)
        troveInfo = store.addTrove(anotherTrove, anotherTrove.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          anotherF.fileId(),
                          v10,
                          fileStream=f1.freeze())
        store.addTroveDone(troveInfo)
        rc = store._removeTrove("another:comp", v10, flavor)
        assert (not rc)
        state = _dbStatus(store.db)
        _checkStateDiff(state, twoTroveState)

        store.db.rollback()

        # now try just marking something as removed
        rc = store.markTroveRemoved("trv:comp", v20, flavor)
        assert (not rc)
        removedTrove = store.getTrove("trv:comp", v20, flavor)
        assert (removedTrove.type() == trove.TROVE_TYPE_REMOVED)

        rc = store.markTroveRemoved("trv:comp", v10, flavor)
        assert (set(rc) == set([f1.contents.sha1(), f2.contents.sha1()]))
        removedTrove = store.getTrove("trv:comp", v10, flavor)
        assert (removedTrove.type() == trove.TROVE_TYPE_REMOVED)

        store.db.rollback()

        # test removing group-*:source
        anotherTrove = trove.Trove('group-foo:source', v10, flavor, cl)
        anotherF = f1.copy()
        anotherF.inode.owner.set('unowned')
        anotherTrove.addFile(f1.pathId(), "group-foo.recipe", v10,
                             anotherF.fileId())
        troveInfo = store.addTrove(anotherTrove, anotherTrove.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "group-foo.recipe",
                          anotherF.fileId(),
                          v10,
                          fileStream=anotherF.freeze())
        store.addTroveDone(troveInfo)
        rc = store._removeTrove("group-foo:source", v10, flavor)
        assert (not rc)
        state = _dbStatus(store.db)
        _checkStateDiff(state, twoTroveState)

        store.db.rollback()

        groupTrove = trove.Trove('group-foo', v10, flavor, cl)
        groupTrove.addTrove('foo', vOtherRepo, flavor)
        troveInfo = store.addTrove(groupTrove, groupTrove.diff(None)[0])
        store.addTroveDone(troveInfo)
        rc = store._removeTrove("group-foo", v10, flavor)
        state = _dbStatus(store.db)
        _checkStateDiff(state, twoTroveState)
        store.db.rollback()

    def testCommonFiles(self):
        # this test simulates a trove having the ame file in different
        # path locations with only changed mtimes.
        store = self._connect()
        flavor = deps.Flavor()
        version = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")

        baseNames = set(['file'])
        dirNames = set(['/junk1', '/junk2'])

        f = files.FileFromFilesystem("/etc/passwd", self.id)
        trv = trove.Trove("junk:data", version, flavor, None)
        trv.addFile(self.id1, "/junk1/file", version, f.fileId())
        trv.addFile(self.id2, "/junk2/file", version, f.fileId())
        trv.computeDigests()

        store.db.transaction()
        store.addTroveSetStart([], dirNames, baseNames)
        ti = store.addTrove(trv, trv.diff(None)[0])
        f.inode.mtime.set(1)
        ti.addFile(self.id1,
                   "/junk1/file",
                   f.fileId(),
                   version,
                   fileStream=f.freeze())
        f.inode.mtime.set(2)
        ti.addFile(self.id2,
                   "/junk2/file",
                   f.fileId(),
                   version,
                   fileStream=f.freeze())
        store.addTroveDone(ti)
        store.commit()

    def testHidden(self):
        store = self._connect()
        cu = store.db.cursor()

        flavor = deps.Flavor()
        version = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")

        f = files.FileFromFilesystem("/etc/passwd", self.id)
        trv = trove.Trove("junk:data", version, flavor, None)
        trv.computeDigests()

        store.addTroveSetStart([], set(['/etc']), set(['passwd']))
        ti = store.addTrove(trv, trv.diff(None)[0], hidden=True)
        store.addTroveDone(ti)
        store.addTroveSetDone()

        assert (cu.execute("select count(*) from latestcache").fetchall()[0][0]
                == 0)
        assert (cu.execute("select isPresent from instances").fetchall()[0][0]
                == instances.INSTANCE_PRESENT_HIDDEN)

        store.presentHiddenTroves()
        assert (cu.execute("select count(*) from latestcache").fetchall()[0][0]
                == 3)
        assert (cu.execute("select isPresent from instances").fetchall()[0][0]
                == instances.INSTANCE_PRESENT_NORMAL)

    def testDistributedRedirect(self):
        store = self._connect()
        cu = store.db.cursor()

        flavor = deps.Flavor()
        localVer1 = ThawVersion("/localhost@test:trunk/10:1.1-10")
        localVer2 = ThawVersion("/localhost@test:trunk/20:1.2-20")
        remoteVer = ThawVersion("/localhost1@test:trunk/10:1.2-10")

        # this places /localhost1@test:trunk into the branch table, but not
        # the labels table
        trv = trove.Trove("group-foo",
                          localVer1,
                          flavor,
                          None,
                          type=trove.TROVE_TYPE_REDIRECT)
        trv.addRedirect("target", remoteVer.branch(), flavor)
        trv.computeDigests()
        store.addTroveSetStart([], [], [])
        ti = store.addTrove(trv, trv.diff(None)[0], hidden=True)
        store.addTroveDone(ti)

        # and this needs the label to exist
        trv = trove.Trove("group-foo", localVer2, flavor, None)
        trv.addTrove("target", remoteVer, flavor)
        trv.computeDigests()
        ti = store.addTrove(trv, trv.diff(None)[0], hidden=True)
        store.addTroveDone(ti)

    def testDuplicatePaths(self):
        store = self._connect()

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")
        flavor1 = deps.Flavor()
        flavor2 = deps.parseFlavor('is:x86')
        cl = changelog.ChangeLog("test", "*****@*****.**", "Changes\n")
        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)

        trv1 = trove.Trove('testcomp', v10, flavor1, cl)
        trv1.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())

        trv2 = trove.Trove('testcomp', v10, flavor2, cl)
        trv2.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())

        store.db.transaction()
        store.addTroveSetStart([], set(['/bin']), set(['1']))

        troveInfo = store.addTrove(trv1, trv1.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          f1.fileId(),
                          v10,
                          fileStream=f1.freeze())
        store.addTroveDone(troveInfo)

        troveInfo = store.addTrove(trv2, trv2.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          f1.fileId(),
                          v10,
                          fileStream=f1.freeze())
        store.addTroveDone(troveInfo)

        store.addTroveSetDone()
        store.db.commit()

        # make sure the path was inserted into FilePaths and friends once
        cu = store.db.cursor()
        for tbl in ['FilePaths', 'Dirnames', 'Basenames']:
            cu.execute("select count(*) from %s" % tbl)
            self.assertEquals(cu.next()[0], 1)
コード例 #21
0
class SqlDB(rephelp.RepositoryHelper):

    id1 = md5FromString("00010001000100010001000100010001")
    id2 = md5FromString("00010001000100010001000100010002")
    id3 = md5FromString("00010001000100010001000100010003")
    id4 = md5FromString("00010001000100010001000100010004")
    id7 = md5FromString("00010001000100010001000100010007")

    fid1 = sha1FromString("0001000100010001000100010001000100010001")
    fid2 = sha1FromString("0001000100010001000100010001000100010002")
    fid3 = sha1FromString("0001000100010001000100010001000100010003")
    fid4 = sha1FromString("0001000100010001000100010001000100010004")
    fid7 = sha1FromString("0001000100010001000100010001000100010007")

    v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")
    v20 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-20")

    emptyFlavor = deps.Flavor()

    noneTup = (None, None, None)

    def testPins(self):
        def _checkPins(*args):
            assert (db.trovesArePinned(troves) == list(args))

        x86Flavor = deps.parseFlavor('is:x86(cmov)')

        troves = [("first", self.v10, self.emptyFlavor),
                  ("second", self.v20, self.emptyFlavor),
                  ("third", self.v10, x86Flavor)]

        db = sqldb.Database(':memory:')

        for name, ver, flavor in troves:
            ti = db.addTrove(trove.Trove(name, ver, flavor, None))
            db.addTroveDone(ti)

        _checkPins(False, False, False)

        checks = [False] * 3
        for i in range(len(troves)):
            checks[i] = True
            db.pinTroves(*troves[i])
            _checkPins(*checks)

        for i in reversed(range(len(troves))):
            checks[i] = False
            db.pinTroves(*troves[i] + (False, ))
            _checkPins(*checks)

    def testIterAllTroves(self):
        trv1 = self.addComponent('foo:lib', '1')
        trv2 = self.addComponent('foo:debuginfo', '1')
        trv3 = self.addCollection('foo', '1', [':lib', (':debuginfo', False)])
        trv4 = self.addComponent('bar:run', '1', 'bam', filePrimer=1)
        self.updatePkg(['foo', 'bar:run[bam]'])
        db = self.openDatabase()
        assert (set(db.iterAllTroves()) == set(x.getNameVersionFlavor()
                                               for x in [trv1, trv3, trv4]))

    def testDBInstances(self):
        cx = dbstore.connect(":memory:", driver="sqlite")
        cx.loadSchema()
        idb = sqldb.DBInstanceTable(cx)
        idb.addId('fred', 1, 2, [1, 2])
        assert (idb[('fred', 1, 2)] == 1)
        assert (idb.getId(1) == ('fred', 1, 2, 1))
        assert (idb.get(('fred', 1, 2), None) == 1)

        idb.addId('wilma', 5, 6, [1, 2])
        assert (idb[('wilma', 5, 6)] == 2)
        idb.delId(2)
        self.assertRaises(KeyError, idb.__getitem__, ('wilma', 5, 6))
        idb.delId(1)
        assert (idb.get(('fred', 1, 2), None) == None)

    def testDBTroveFiles(self):
        cx = dbstore.connect(":memory:", driver="sqlite")
        cx.loadSchema()
        fs = sqldb.DBTroveFiles(cx)
        cu = cx.cursor()
        fs.addItem(cu, self.id1, 1, "/bin/ls", self.fid1, 11, "abc",
                   ["tag1", "tag2"])
        fs.addItem(cu, self.id2, 2, "/bin/cat", self.fid2, 11, "def", ["tag1"])
        fs.addItem(cu, self.id3, 1, "/bin/dd", self.fid3, 12, "tuv", [])
        fs.addItem(cu, self.id4, 2, "/bin/bc", self.fid4, 12, "xyz", [])
        assert ([x for x in fs[11]] == [("/bin/ls", "abc"),
                                        ("/bin/cat", "def")])
        assert ([x for x in fs[12]] == [("/bin/dd", "tuv"),
                                        ("/bin/bc", "xyz")])
        assert ([x for x in fs.iterFilesWithTag('tag1')
                 ] == ['/bin/cat', '/bin/ls'])
        assert ([x for x in fs.iterFilesWithTag('tag2')] == ['/bin/ls'])

        fs.delInstance(11)
        assert ([x for x in fs[11]] == [])

        # make sure the tags are gone
        assert ([x for x in fs.iterFilesWithTag('tag1')] == [])
        cu = cx.cursor()
        cu.execute('select * from DBFileTags')
        assert ([x for x in cu] == [])

        assert (fs.getFileByFileId(self.fid3, 0) == ("/bin/dd", "tuv"))
        self.assertRaises(KeyError, fs.getFileByFileId, self.fid7, 0)

        assert ([x for x in fs[12]] == [("/bin/dd", "tuv"),
                                        ("/bin/bc", "xyz")])
        fs.removePath(12, "/bin/dd")
        assert ([x for x in fs.getByInstanceId(12)] == [("/bin/bc", "xyz")])
        assert (fs.getFileByFileId(self.fid4,
                                   justPresent=False) == ('/bin/bc', 'xyz'))
        assert ([x for x in fs.getByInstanceId(12, justPresent=False)
                 ] == [("/bin/dd", "tuv"), ("/bin/bc", "xyz")])
        fs.delInstance(12)

        fs.addItem(cu, self.id1, 1, "/bin/ls", self.fid1, 11, "abc", [])
        fs.addItem(cu, self.id2, 2, "/bin/cat", self.fid2, 11, "def", [])
        fs.addItem(cu, self.id3, 1, "/bin/dd", self.fid3, 11, "tuv", [])
        fs.addItem(cu, self.id4, 2, "/bin/bc", self.fid4, 11, "xyz", [])
        assert ([x
                 for x in fs[11]] == [("/bin/ls", "abc"), ("/bin/cat", "def"),
                                      ("/bin/dd", "tuv"), ("/bin/bc", "xyz")])

    def testDatabase1(self):
        db = sqldb.Database(':memory:')

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)
        f2 = files.FileFromFilesystem("/etc/services", self.id2)
        f3 = files.FileFromFilesystem("/etc/group", self.id3)

        trv = trove.Trove("testcomp", self.v10, self.emptyFlavor, None)
        trv.addFile(self.id1, "/bin/1", self.v10, f1.fileId())
        trv.addFile(self.id2, "/bin/2", self.v10, f2.fileId())
        trv.addFile(self.id3, "/bin/3", self.v10, f3.fileId())
        trv.troveInfo.size.set(1234)
        trv.troveInfo.sourceName.set('thesource')

        req = deps.DependencySet()
        req.addDep(deps.FileDependencies, deps.Dependency("/bin/bash"))
        req.addDep(deps.TroveDependencies, deps.Dependency("foo:runtime"))
        req.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setRequires(req)

        trvInfo = db.addTrove(trv)

        db.addFile(trvInfo,
                   f1.pathId(),
                   "/bin/1",
                   f1.fileId(),
                   self.v10,
                   fileStream=f1.freeze())
        db.addFile(trvInfo,
                   f2.pathId(),
                   "/bin/2",
                   f2.fileId(),
                   self.v10,
                   fileStream=f2.freeze())
        db.addFile(trvInfo,
                   f3.pathId(),
                   "/bin/3",
                   f3.fileId(),
                   self.v10,
                   fileStream=f3.freeze())

        db.addTroveDone(trvInfo)

        dbTrv = db.getTroves([("testcomp", self.v10, self.emptyFlavor)])[0]
        assert (dbTrv == trv)
        assert (dbTrv.__class__ == trove.Trove)
        assert (db.trovesArePinned([("testcomp", self.v10, self.emptyFlavor)
                                    ]) == [False])
        dbTrv = db.getTroves([("testcomp", self.v10, self.emptyFlavor)],
                             withFileObjects=True)[0]
        assert (dbTrv == trv)
        assert (dbTrv.__class__ == trove.TroveWithFileObjects)
        for f in (f1, f2, f3):
            assert (dbTrv.getFileObject(f.fileId()) == f)

        trv2 = trove.Trove("testpkg", self.v10, self.emptyFlavor, None)
        ti = trv2.addTrove(trv.getName(), self.v10, trv.getFlavor())
        trv2.addTrove("weakref", self.v10, trv.getFlavor(), weakRef=True)
        ti = db.addTrove(trv2, pin=True)
        db.addTroveDone(ti)
        assert (db.trovesArePinned([("testpkg", self.v10, self.emptyFlavor)
                                    ]) == [True])
        assert (db.getTroves([("testpkg", self.v10, self.emptyFlavor)
                              ])[0] == trv2)
        assert (db.getTroves([
            ("testpkg", self.v10, self.emptyFlavor)
        ])[0].getVersion().timeStamps() == trv2.getVersion().timeStamps())

        assert (db.getTroves([("testpkg", self.v10, self.emptyFlavor),
                              ("testcomp", self.v10, self.emptyFlavor),
                              ("testitem", self.v10, self.emptyFlavor)],
                             True) == [trv2, trv, None])

        assert (db.getTroves([("testpkg", self.v10, self.emptyFlavor),
                              ("testcomp", self.v10, req)],
                             True) == [trv2, None])

        assert (db.findTroveContainers(["testpkg",
                                        "testcomp"]) == [[],
                                                         [("testpkg", self.v10,
                                                           self.emptyFlavor)]])

        assert (db.getTroveContainers([
            ("testpkg", self.v10, self.emptyFlavor),
            ("testcomp", self.v10, self.emptyFlavor)
        ]) == [[], [("testpkg", self.v10, self.emptyFlavor)]])

        res = db.findTroveReferences(["testpkg", "testcomp"])

        assert (db.findTroveReferences(["testpkg", "testcomp"
                                        ]) == [[],
                                               [("testcomp", self.v10,
                                                 self.emptyFlavor)]])

        v10new = VersionFromString("/conary.rpath.com@test:trunk/1.2-10")
        assert (db.getTroves([("testpkg", v10new, self.emptyFlavor)
                              ])[0] == trv2)
        assert (db.getTroves([
            ("testpkg", v10new, self.emptyFlavor)
        ])[0].getVersion().timeStamps() == trv2.getVersion().timeStamps())

        assert (set(db.findByNames(['testpkg', 'testcomp'])) == set([
            ("testpkg", self.v10, self.emptyFlavor),
            ("testcomp", self.v10, self.emptyFlavor)
        ]))

        db.eraseTrove("testcomp", self.v10, None)
        assert (db.getTroves([("testpkg", self.v10, self.emptyFlavor)
                              ])[0] == trv2)

        trv.computePathHashes()
        trvInfo = db.addTrove(trv)
        db.addFile(trvInfo,
                   f1.pathId(),
                   "/bin/1",
                   f1.fileId(),
                   self.v10,
                   fileStream=f1.freeze())
        db.addFile(trvInfo,
                   f2.pathId(),
                   "/bin/2",
                   f2.fileId(),
                   self.v10,
                   fileStream=f1.freeze())
        db.addFile(trvInfo,
                   f3.pathId(),
                   "/bin/3",
                   f3.fileId(),
                   self.v10,
                   fileStream=f1.freeze())
        db.addTroveDone(trvInfo)

        assert (db.getTroves([("testcomp", self.v10, self.emptyFlavor)
                              ])[0] == trv)
        db.removeFileFromTrove(trv, "/bin/1")
        changedTrv = db.getTroves([trv.getNameVersionFlavor()],
                                  pristine=False)[0]
        otherChangedTrv = db.getTroves([trv.getNameVersionFlavor()],
                                       withFiles=False,
                                       pristine=False)[0]
        assert (len(changedTrv.idMap) + 1 == len(trv.idMap))
        assert (len(changedTrv.troveInfo.pathHashes) + 1 == len(
            trv.troveInfo.pathHashes))
        assert (changedTrv.troveInfo.pathHashes ==
                otherChangedTrv.troveInfo.pathHashes)
        assert (len(otherChangedTrv.idMap) == 0)
        changedTrv.addFile(self.id1, "/bin/1", self.v10, f1.fileId())
        assert (changedTrv.idMap == trv.idMap)
        changedTrv.computePathHashes()
        assert (changedTrv.troveInfo.pathHashes == trv.troveInfo.pathHashes)

        assert (db.getTroves([("testcomp", self.v10, self.emptyFlavor)],
                             pristine=True)[0] == trv)
        db.eraseTrove("testpkg", self.v10, None)
        assert (db.getTroves([("testpkg", self.v10, self.emptyFlavor)
                              ]) == [None])
        self.assertRaises(KeyError, db.instances.getVersion, 100)

        db.eraseTrove("testcomp", self.v10, None)
        db.commit()
        cu = db.db.cursor()

        # make sure the versions got removed; the None entry is still there
        cu.execute("SELECT count(*) FROM Versions")
        assert (cu.next()[0] == 1)

        # make sure the dependency table got cleaned up
        cu.execute("SELECT count(*) FROM Dependencies")
        assert (cu.next()[0] == 0)

        # make sure the instances table got cleaned up
        cu.execute("SELECT count(*) FROM Instances")
        assert (cu.next()[0] == 0)

        # make sure the troveInfo table got cleaned up
        cu.execute("SELECT count(*) FROM TroveInfo")
        assert (cu.next()[0] == 0)

    def testDatabase2(self):
        db = sqldb.Database(':memory:')

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)
        f2 = files.FileFromFilesystem("/etc/services", self.id2)
        f3 = files.FileFromFilesystem("/etc/group", self.id3)

        trv = trove.Trove("testcomp", self.v10, self.emptyFlavor, None)
        trv.addFile(self.id1, "/bin/1", self.v10, f1.fileId())
        trv.addFile(self.id2, "/bin/2", self.v10, f2.fileId())
        trv.addFile(self.id3, "/bin/3", self.v10, f3.fileId())
        trvInfo = db.addTrove(trv)

        db.addFile(trvInfo,
                   f1.pathId(),
                   "/bin/1",
                   f1.fileId(),
                   self.v10,
                   fileStream=f1.freeze())
        db.addFile(trvInfo,
                   f2.pathId(),
                   "/bin/2",
                   f2.fileId(),
                   self.v10,
                   fileStream=f2.freeze())
        db.addFile(trvInfo,
                   f3.pathId(),
                   "/bin/3",
                   f3.fileId(),
                   self.v10,
                   fileStream=f3.freeze())

        db.addTroveDone(trvInfo)

        assert (db.getTroves([("testcomp", self.v10, self.emptyFlavor),
                              ("testcomp", self.v20, self.emptyFlavor)],
                             True) == [trv, None])
        assert (db.hasTroves([("testcomp", self.v10, self.emptyFlavor),
                              ("testcomp", self.v20, self.emptyFlavor)
                              ]) == [True, False])

        f2 = files.FileFromFilesystem("/etc/hosts", self.id2)

        trv2 = trove.Trove("testcomp", self.v20, self.emptyFlavor, None)
        trv2.addFile(self.id1, "/bin/1", self.v10, self.fid1)
        trv2.addFile(self.id2, "/bin/2", self.v20, self.fid2)

        #trvInfo = db.addTrove(trv2)
        #db.addFile(trvInfo, f2.pathId(), f2, "/bin/2", self.v20)

        #assert(db.getTrove("testcomp", self.v20, None) == trv2)

    def testDatabaseTransactionCounter(self):
        db = sqldb.Database(':memory:')
        field = 'transaction counter'
        # We should have a row
        cu = db.db.cursor()
        cu.execute("SELECT value FROM DatabaseAttributes WHERE name = ?",
                   field)
        row = cu.next()
        self.assertEqual(row[0], '0')

        updateq = "UPDATE DatabaseAttributes SET value = ? WHERE name = ?"
        # Update it manually
        cu.execute(updateq, '10', field)
        db.db.commit()

        self.assertEqual(db.getTransactionCounter(), 10)

        # Increment it
        self.assertEqual(db.incrementTransactionCounter(), 11)
        self.assertEqual(db.getTransactionCounter(), 11)

        # Delete entry, should reset the counter
        cu.execute("DELETE from DatabaseAttributes WHERE name = ?", field)
        db.db.commit()
        self.assertEqual(db.getTransactionCounter(), 0)
        self.assertEqual(db.incrementTransactionCounter(), 1)
        self.assertEqual(db.getTransactionCounter(), 1)

        self.assertEqual(db.incrementTransactionCounter(), 2)
        self.assertEqual(db.getTransactionCounter(), 2)

        # Mess it up
        cu.execute(updateq, 'not an integer', field)
        self.assertEqual(db.getTransactionCounter(), 0)
        self.assertEqual(db.incrementTransactionCounter(), 1)
        self.assertEqual(db.getTransactionCounter(), 1)

    def testDatabaseTroveInfoCleanup(self):
        # remove a trove but leave a reference - its troveInfo data
        # should be removed
        flavor1 = deps.parseFlavor('is:x86(cmov)')
        db = sqldb.Database(':memory:')
        trv1 = trove.Trove("testcomp:runtime", self.v10, flavor1, None)
        trvInfo = db.addTrove(trv1)
        db.addTroveDone(trvInfo)
        trv2 = trove.Trove("testcomp", self.v10, flavor1, None)
        trv2.addTrove(*trv1.getNameVersionFlavor())
        trvInfo = db.addTrove(trv2)
        db.addTroveDone(trvInfo)
        db.commit()

        db.eraseTrove("testcomp:runtime", self.v10, flavor1)
        db.commit()

        cu = db.db.cursor()
        cu.execute('select count(*) from instances join troveInfo '
                   'using(instanceId) where troveName="testcomp:runtime"')
        assert (not cu.fetchall()[0][0])

    def testDatabaseVersionCleanup(self):
        flavor1 = deps.parseFlavor('is:x86(cmov)')
        db = sqldb.Database(':memory:')
        cu = db.db.cursor()
        v10 = ThawVersion('/conary.rpath.com@test:trunk/10:1.2-10')
        v20 = ThawVersion('/conary.rpath.com@test:trunk/10:1.2-20')
        v30 = ThawVersion('/conary.rpath.com@test:trunk/10:1.2-30')

        # test file version cleanup
        trv = trove.Trove('testcomp:runtime', v10, flavor1, None)
        f1 = files.FileFromFilesystem('/etc/passwd', self.id1)
        f2 = files.FileFromFilesystem('/etc/services', self.id2)
        f3 = files.FileFromFilesystem('/etc/group', self.id3)
        trv.addFile(self.id1, '/bin/1', v10, f1.fileId())
        trv.addFile(self.id2, '/bin/2', v20, f2.fileId())
        trv.addFile(self.id3, '/bin/3', v30, f3.fileId())
        trvInfo = db.addTrove(trv)
        db.addFile(trvInfo,
                   f1.pathId(),
                   '/bin/1',
                   f1.fileId(),
                   v10,
                   fileStream=f1.freeze())
        db.addFile(trvInfo,
                   f2.pathId(),
                   '/bin/2',
                   f2.fileId(),
                   v20,
                   fileStream=f2.freeze())
        db.addFile(trvInfo,
                   f3.pathId(),
                   '/bin/3',
                   f3.fileId(),
                   v30,
                   fileStream=f3.freeze())
        db.addTroveDone(trvInfo)
        # check to see how many versions we have
        cu.execute('select count(*) from Versions')
        count = cu.fetchall()[0][0]
        # should have only 0|NULL
        self.assertEqual(count, 4)
        # now erase
        db.eraseTrove('testcomp:runtime', v10, flavor1)
        db.commit()
        cu.execute('select count(*) from Versions')
        count = cu.fetchall()[0][0]
        # should have only 0|NULL
        self.assertEqual(count, 1)

        # test trove version cleanup
        trv1 = trove.Trove('testcomp:runtime', v10, flavor1, None)
        trv2 = trove.Trove('group-test', v20, flavor1, None)
        trv2.addTrove(trv1.getName(),
                      trv1.getVersion(),
                      trv1.getFlavor(),
                      weakRef=True)
        trvInfo = db.addTrove(trv2)
        db.addTroveDone(trvInfo)
        db.commit()
        cu.execute('select count(*) from Versions')
        count = cu.fetchall()[0][0]
        self.assertEqual(count, 3)

        db.eraseTrove('group-test', v20, flavor1)
        db.commit()
        cu.execute('select count(*) from Versions')
        count = cu.fetchall()[0][0]
        # should have only 0|NULL
        self.assertEqual(count, 1)

    def testMultipleFlavorsInstalled(self):
        """
        verify that only one (unique) flavor is returned from
        db.iterVersionByName if multiple troves with the same version
        but different flavors are installed at the same time
        """
        db = sqldb.Database(':memory:')
        flavor1 = deps.parseFlavor('is:x86(cmov)')
        flavor2 = deps.parseFlavor('is:x86(sse)')
        trv1 = trove.Trove("testcomp", self.v10, flavor1, None)
        trv2 = trove.Trove("testcomp", self.v10, flavor2, None)
        ti = db.addTrove(trv1)
        db.addTroveDone(ti)
        ti = db.addTrove(trv2)
        db.addTroveDone(ti)
        assert ([x for x in db.iterVersionByName('testcomp', False)
                 ] == [self.v10])
        assert ([x for x in db.iterVersionByName('testcomp', True)
                 ] == [(self.v10, flavor1), (self.v10, flavor2)])

    def testGroupMissingComponent(self):
        flavor1 = deps.parseFlavor('is:x86(cmov)')
        db = sqldb.Database(':memory:')
        trv1 = trove.Trove("group1", self.v10, flavor1, None)
        ti = trv1.addTrove("subcomp", self.v10, flavor1)
        ti = trv1.addTrove("subcomp2", self.v10, flavor1)
        ti = trv1.addTrove("subcomp3", self.v10, flavor1, weakRef=True)
        ti = db.addTrove(trv1)
        db.addTroveDone(ti)

        trv2 = trove.Trove("group2", self.v10, flavor1, None)
        trv2.addTrove("subcomp", self.v10, flavor1, weakRef=True)
        ti = db.addTrove(trv2)
        db.addTroveDone(ti)

        trv3 = trove.Trove("subcomp2", self.v10, flavor1, None)
        ti = db.addTrove(trv3)
        db.addTroveDone(ti)

        inst, instRefed, strongMissing, weakMissing = db.getCompleteTroveSet(
            ["group1", "subcomp", "subcomp2", "subcomp3"])

        assert (inst == set([("group1", self.v10, flavor1)]))
        # this ensures the version returns has timestamps on it
        assert ([x for x in inst][0][1].freeze())
        assert (strongMissing == set([("subcomp", self.v10, flavor1)]))
        assert (weakMissing == set([("subcomp3", self.v10, flavor1)]))
        assert (instRefed == set([("subcomp2", self.v10, flavor1)]))

    def testVersion2Migration(self):
        dbfile = os.path.join(resources.get_archive(), 'conarydbs',
                              'conarydb-version-2')
        fd, fn = tempfile.mkstemp()
        os.close(fd)
        shutil.copyfile(dbfile, fn)
        db, str = self.captureOutput(sqldb.Database, fn)
        cu = db.db.cursor()
        # make sure that the -*none*- entry has been added
        cu.execute(
            'select count(*) from provides join dependencies on provides.depid=dependencies.depid and name="sqlite:lib" and flag="-*none*-"'
        )
        assert (cu.next() == (1, ))
        db.close()
        os.unlink(fn)

    def testVersion3Migration(self):
        dbfile = os.path.join(resources.get_archive(), 'conarydbs',
                              'conarydb-version-3')
        fd, fn = tempfile.mkstemp()
        os.close(fd)
        shutil.copyfile(dbfile, fn)
        db, str = self.captureOutput(sqldb.Database, fn)
        cu = db.db.cursor()
        db.close()
        os.unlink(fn)

    def testVersion11Migration(self):
        dbfile = os.path.join(resources.get_archive(), 'conarydbs',
                              'conarydb-version-11')
        fd, fn = tempfile.mkstemp()
        os.close(fd)
        shutil.copyfile(dbfile, fn)
        db, str = self.captureOutput(sqldb.Database, fn)
        cu = db.db.cursor()

        # make sure there aren't any install buckets left
        cu.execute("select count(*) from troveinfo where infoType=?",
                   trove._TROVEINFO_TAG_INSTALLBUCKET)
        assert (cu.next()[0] == 0)

        # make sure the path hashs look right for libpng:lib
        cu.execute(
            "select data from troveinfo, instances where "
            "trovename='libpng:lib' and "
            "troveinfo.instanceid=instances.instanceid "
            "and infoType=?", trove._TROVEINFO_TAG_PATH_HASHES)
        ph = trove.PathHashes(cu.next()[0])

        cu.execute("select path from instances, dbtrovefiles where "
                   "instances.instanceid=dbtrovefiles.instanceid "
                   "and troveName='libpng:lib'")
        for path, in cu:
            hash = md5String(path)[:8]
            assert (hash in ph)
            ph.remove(hash)

        assert (not ph)

        db.close()
        os.unlink(fn)

    def testVersion20Migration(self):
        dbfile = os.path.join(resources.get_archive(), 'conarydbs',
                              'conarydb-version-19')
        fd, fn = tempfile.mkstemp()
        os.close(fd)
        shutil.copyfile(dbfile, fn)
        # get a list of tables
        db = dbstore.connect(fn, driver='sqlite')
        db.loadSchema()
        cu = db.cursor()
        tableCounts = dict.fromkeys(db.tables.keys())
        for table in tableCounts.keys():
            tableCounts[table] = cu.execute('select count(*) from %s' %
                                            table).fetchall()[0][0]
        # DBInstances is gone...
        tableCounts.pop('DBInstances')
        # we have a VersionId 0 entry now
        tableCounts['Versions'] += 1
        # new table added
        tableCounts['DatabaseAttributes'] = 1

        # do the migration
        db, str = self.captureOutput(sqldb.Database, fn)
        cu = db.db.cursor()

        # make sure we have all the tables
        db2 = dbstore.connect(fn, driver='sqlite')
        db2.loadSchema()
        cu = db2.cursor()
        tableCounts2 = dict.fromkeys(db2.tables.keys())
        for table in tableCounts2.keys():
            tableCounts2[table] = cu.execute('select count(*) from %s' %
                                             table).fetchall()[0][0]
        self.assertEqual(tableCounts, tableCounts2)

        # check to make sure that we fixed our broken deps and troveinfo
        cu.execute("select count(*) from troveinfo where infoType=3 "
                   "and hex(data) == '31'")
        assert (cu.next()[0] == 0)
        cu.execute("select count(*) from dependencies where "
                   "name like 'conary:%' and flag='1'")
        assert (cu.next()[0] == 0)

        # verify the conary:runtime trove
        v = VersionFromString('/conary.rpath.com@rpl:devel//1/1.0-2-0.1')
        f = deps.parseFlavor('~!bootstrap is: x86')
        t = db.getTroves([('conary:runtime', v, f)])[0]
        t.verifyDigitalSignatures()

        # verify that we can insert a '1.0' into deps and troveinfo
        cu.execute("insert into Dependencies values (NULL, 4, 'test', '1.0')")
        cu.execute("select flag from Dependencies where name='test'")
        assert (cu.next()[0] == '1.0')

        cu.execute("insert into TroveInfo values (300, 3, '1.0')")
        cu.execute("select data from TroveInfo where instanceId=300 and "
                   "infotype=3")
        assert (cu.next()[0] == '1.0')

        db.close()
        db2.close()

        # make sure the addition of DatabaseAttributes happens correctly
        db = dbstore.connect(fn, driver='sqlite')
        db.loadSchema()
        self.assertTrue('DatabaseAttributes' in db.tables)
        cu = db.cursor()
        cu.execute("DROP TABLE DatabaseAttributes")
        db.commit()
        db.close()

        sdb = sqldb.Database(fn)
        self.assertTrue('DatabaseAttributes' in sdb.db.tables)
        del sdb

        os.unlink(fn)

    def testVersion20DeAnalyze(self):
        dbfile = os.path.join(resources.get_archive(), 'conarydbs',
                              'conarydb-version-20-with-analyze')
        fd, fn = tempfile.mkstemp()
        os.close(fd)
        shutil.copyfile(dbfile, fn)
        db = sqldb.Database(fn)
        cu = db.db.cursor()
        cu.execute('select count(*) from sqlite_stat1')
        count = cu.fetchall()[0][0]
        self.assertEqual(count, 0)
        db.close()
        os.unlink(fn)

    def testMigrationReadOnly(self):
        dbfile = os.path.join(resources.get_archive(), 'conarydbs',
                              'conarydb-version-2')
        fd, fn = tempfile.mkstemp()
        os.close(fd)
        shutil.copyfile(dbfile, fn)
        os.chmod(fn, 0444)
        try:
            db = sqldb.Database(fn)
        except sqldb.OldDatabaseSchema:
            pass
        else:
            raise
        os.unlink(fn)

    def testSubtroveUpdates(self):
        db = sqldb.Database(':memory:')

        pkg = trove.Trove("testpkg", self.v10, self.emptyFlavor, None)
        pkg.addTrove("testpkg:comp", self.v10, self.emptyFlavor)
        ti = db.addTrove(pkg)
        db.addTroveDone(ti)

        comp1 = trove.Trove("testpkg:comp", self.v10, self.emptyFlavor, None)
        ti = db.addTrove(comp1)
        db.addTroveDone(ti)
        comp2 = trove.Trove("testpkg:comp", self.v20, self.emptyFlavor, None)
        ti = db.addTrove(comp1)
        db.addTroveDone(ti)
        #
        ti = db.addTrove(
            #("testpkg:comp", self.v10, self.emptyFlavor),
            comp2)
        db.addTroveDone(ti)
        db.eraseTrove("testpkg:comp", self.v10, self.emptyFlavor)

        pristinePkg = db.getTroves([("testpkg", self.v10, self.emptyFlavor)],
                                   pristine=True)[0]
        instPkg = db.getTroves([("testpkg", self.v10, self.emptyFlavor)],
                               pristine=False)[0]
        assert (pristinePkg == pkg)
        assert (instPkg != pkg)

        ti = db.addTrove(
            #("testpkg:comp", self.v20, self.emptyFlavor),
            comp1)
        db.addTroveDone(ti)
        db.eraseTrove("testpkg:comp", self.v20, self.emptyFlavor)

        pristinePkg = db.getTroves([("testpkg", self.v10, self.emptyFlavor)],
                                   pristine=True)[0]
        instPkg = db.getTroves([("testpkg", self.v10, self.emptyFlavor)],
                               pristine=False)[0]
        assert (pristinePkg == pkg)
        assert (instPkg == pkg)

        # make sure there aren't broken bits in TroveTroves
        assert (db.db.cursor().execute(
            "select count(*) from trovetroves").next()[0] == 1)

    def testMapPinned(self):
        # test to ensure that a if you update a pinned trove twice,
        # a duplicate entry does not show up in TroveTroves.
        db = sqldb.Database(':memory:')

        pkg = trove.Trove("testpkg", self.v20, self.emptyFlavor, None)
        pkg.addTrove("testpkg:comp", self.v20, self.emptyFlavor)
        ti = db.addTrove(pkg)
        db.addTroveDone(ti)

        comp1 = trove.Trove("testpkg:comp", self.v10, self.emptyFlavor, None)
        ti = db.addTrove(comp1)
        db.addTroveDone(ti)
        # we've got a trove with a link from trove to component.
        # we assume the component was pinned at v10...now we need to update
        # the link to point to the v10 ver.
        db.mapPinnedTroves([('testpkg:comp', (self.v10, self.emptyFlavor),
                             (self.v20, self.emptyFlavor))])
        cu = db.db.cursor()
        assert (
            cu.execute('SELECT COUNT(*) FROM TroveTroves WHERE inPristine=0'
                       ).next()[0] == 1)
        db.mapPinnedTroves([('testpkg:comp', (self.v10, self.emptyFlavor),
                             (self.v20, self.emptyFlavor))])
        assert (
            cu.execute('SELECT COUNT(*) FROM TroveTroves WHERE inPristine=0'
                       ).next()[0] == 1)
        pkg = db.getTroves([('testpkg', self.v20, self.emptyFlavor)],
                           pristine=False)[0]
        assert (pkg.strongTroves.keys()[0][1] == self.v10)
        assert (pkg.weakTroves.keys() == [])
コード例 #22
0
ファイル: rpmcapsule.py プロジェクト: fedora-conary/conary
 def _digest(rpmlibHeader):
     if rpmhelper.SIG_SHA1 in rpmlibHeader.keys():
         return sha1helper.sha1FromString(
                 rpmlibHeader[rpmhelper.SIG_SHA1])
     else:
         return None
コード例 #23
0
    def testTroves(self, flavor=None):
        if flavor is None:
            flavor = deps.Flavor()

        store = self._connect()

        dirSet = set(['/etc', '/bin'])
        baseSet = set(
            ['passwd', 'services', 'group', '1', '2', '3', 'distributed'])

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")

        branch = v10.branch()
        store.createTroveBranch("testtrove", branch)

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)
        f2 = files.FileFromFilesystem("/etc/services", self.id2)
        f3 = files.FileFromFilesystem("/etc/group", self.id3)
        # make a really huge dependency, thus a very large file stream
        req = deps.DependencySet()
        for x in xrange(10000):
            req.addDep(deps.SonameDependencies,
                       deps.Dependency("libtest.so.%d" % x))
        f3.requires.set(req)
        # make sure it's way too big for a blob in mysql
        assert (len(f3.freeze()) >= 50000)

        cl = changelog.ChangeLog(
            "test", "*****@*****.**", """\
Some changes are good.
Some changes are bad.
Some changes just are.
""")

        trv = trove.Trove('testcomp', v10, flavor, cl)
        trv.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())
        trv.addFile(f2.pathId(), "/bin/2", v10, f2.fileId())
        trv.addFile(f3.pathId(), "/bin/3", v10, f3.fileId())
        trv.addFile(self.id4, "/bin/distributed", v10, self.fid4)
        trv.troveInfo.size.set(1234)
        trv.troveInfo.sourceName.set('somesource')

        req = deps.DependencySet()
        req.addDep(deps.FileDependencies, deps.Dependency("/bin/bash"))
        req.addDep(deps.TroveDependencies, deps.Dependency("foo:runtime"))
        req.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setRequires(req)

        # this also lets us peek at the database to make sure libtest.so.1
        # is only in the dep table once
        prv = deps.DependencySet()
        prv.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setProvides(prv)
        trv.computeDigests()

        store.db.transaction()
        store.addTroveSetStart([], dirSet, baseSet)
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        troveInfo.addFile(f1.pathId(),
                          "/bin/1",
                          f1.fileId(),
                          v10,
                          fileStream=f1.freeze())
        troveInfo.addFile(f2.pathId(),
                          "/bin/2",
                          f2.fileId(),
                          v10,
                          fileStream=f2.freeze())
        troveInfo.addFile(f3.pathId(),
                          "/bin/3",
                          f3.fileId(),
                          v10,
                          fileStream=f3.freeze())
        troveInfo.addFile(self.id4, "/bin/distributed", self.fid4, v10)
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        store.db.commit()

        cu = store.db.cursor()
        cu.execute("SELECT count(*) FROM Dependencies WHERE "
                   "name = 'libtest.so.1'")
        self.assertEqual(cu.next(), (1, ))

        # make sure the sha1s were stored
        cu.execute("""
        SELECT dirname, basename, sha1
        FROM TroveFiles
        JOIN FileStreams USING (streamId)
        JOIN FilePaths ON TroveFiles.filePathId = FilePaths.filePathId
        JOIN Dirnames ON FilePaths.dirnameId = Dirnames.dirnameId
        JOIN Basenames ON FilePaths.basenameId = Basenames.basenameId
        ORDER BY dirname,basename""")
        items = [(os.path.join(cu.frombinary(x[0]),
                               cu.frombinary(x[1])), cu.frombinary(x[2]))
                 for x in cu.fetchall()]
        self.assertEqual(items, [("/bin/1", f1.contents.sha1()),
                                 ("/bin/2", f2.contents.sha1()),
                                 ("/bin/3", f3.contents.sha1()),
                                 ("/bin/distributed", None)])

        cl = changelog.ChangeLog("test", "*****@*****.**", "another log\n")

        fromRepos = store.getTrove("testcomp", v10, flavor, cl)
        self.assertEqual(fromRepos, trv)
        self.assertEqual(fromRepos.getVersion().timeStamps(),
                         trv.getVersion().timeStamps())
        self.assertEqual(fromRepos.getChangeLog(), trv.getChangeLog())

        self.assertEqual([
            x for x in store.getTrove("testcomp", v10, flavor,
                                      withFiles=False).iterFileList()
        ], [])

        l = store.iterFilesInTrove("testcomp", v10, flavor, sortByPath=True)
        l = [x for x in l]
        self.assertEqual(l, [(f1.pathId(), "/bin/1", f1.fileId(), v10),
                             (f2.pathId(), "/bin/2", f2.fileId(), v10),
                             (f3.pathId(), "/bin/3", f3.fileId(), v10),
                             (self.id4, "/bin/distributed", self.fid4, v10)])

        cl = changelog.ChangeLog("test", "*****@*****.**", "log for testpkg\n")
        trv2 = trove.Trove("testpkg", v10, flavor, cl)
        trv2.addTrove(trv.getName(), v10, flavor)
        trv2.addTrove("weakref", v10, flavor, weakRef=True)
        trv2.computeDigests()
        store.addTroveSetStart([], dirSet, baseSet)
        troveInfo = store.addTrove(trv2, trv2.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        self.assertEqual(store.getTrove("testpkg", v10, flavor), trv2)

        self.assertEqual([
            x for x in store.iterTroves([("testcomp", v10,
                                          flavor), ("testpkg", v10, flavor)])
        ], [trv, trv2])
        self.assertEqual([
            x for x in store.iterTroves([("testpkg", v10,
                                          flavor), ("testcomp", v10, flavor)])
        ], [trv2, trv])
        self.assertEqual([
            x for x in store.iterTroves([("testpkg", v10,
                                          flavor), ("testpkg", v10, flavor)])
        ], [trv2, trv2])
        self.assertEqual([
            x for x in store.iterTroves([("testpkg", v10,
                                          flavor), ("blah", v10, flavor)])
        ], [trv2, None])
        self.assertEqual([
            x for x in store.iterTroves([("blah", v10,
                                          flavor), ("testpkg", v10, flavor)])
        ], [None, trv2])
        self.assertEqual(
            [x for x in store.iterTroves([("blah", v10, flavor)])], [None])
        self.assertEqual([
            x for x in store.iterTroves([(
                "testcomp", v10, flavor), ("blah", v10,
                                           flavor), ("testpkg", v10, flavor)])
        ], [trv, None, trv2])

        # erasing doesn't work
        #store.eraseTrove("testcomp", v10, None)
        #store.commit()
        self.assertEqual(store.getTrove("testpkg", v10, flavor), trv2)

        map = {'testpkg': [v10]}
        flavors = store.getTroveFlavors(map)
        if flavor is not None:
            flavorStr = flavor.freeze()
        else:
            flavorStr = ''
        self.assertEqual(flavors, {'testpkg': {v10: [flavorStr]}})

        map = {'testpkg3': [v10]}
        flavors = store.getTroveFlavors(map)
        self.assertEqual(flavors, {'testpkg3': {v10: []}})

        # test getFiles
        fileObjs = store.getFiles([(f1.pathId(), f1.fileId()),
                                   (f2.pathId(), f2.fileId())])
        self.assertEqual(fileObjs[(f1.pathId(), f1.fileId())], f1)
        self.assertEqual(fileObjs[(f2.pathId(), f2.fileId())], f2)

        # test that asking for an invalid fileid/pathid pair results
        # in no entry for the (pathid, fileid) in the returned dict
        invalidPathId = md5FromString('9' * 32)
        invalidFileId = sha1FromString('9' * 40)
        fileObjs = store.getFiles([(invalidPathId, invalidFileId)])
        # make sure fileObjs is empty
        assert (not fileObjs)

        # test that asking for contents that have to come from
        # a different repository works - we should get None
        # back
        fileObjs = store.getFiles([(self.id4, self.fid4)])
        self.assertEqual(fileObjs, {(self.id4, self.fid4): None})
コード例 #24
0
ファイル: trovestoretest.py プロジェクト: pombr/conary
    def testTroves(self, flavor=None):
        if flavor is None:
            flavor = deps.Flavor()

        store = self._connect()

        dirSet = set(['/etc', '/bin'])
        baseSet = set(['passwd', 'services', 'group', '1', '2', '3',
                       'distributed'])

        v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10")

        branch = v10.branch()
        store.createTroveBranch("testtrove", branch)

        f1 = files.FileFromFilesystem("/etc/passwd", self.id1)
        f2 = files.FileFromFilesystem("/etc/services", self.id2)
        f3 = files.FileFromFilesystem("/etc/group", self.id3)
        # make a really huge dependency, thus a very large file stream
        req = deps.DependencySet()
        for x in xrange(10000):
            req.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.%d" %x))
        f3.requires.set(req)
        # make sure it's way too big for a blob in mysql
        assert(len(f3.freeze()) >= 50000)

        cl = changelog.ChangeLog("test", "*****@*****.**", """\
Some changes are good.
Some changes are bad.
Some changes just are.
""")

        trv = trove.Trove('testcomp', v10, flavor, cl)
        trv.addFile(f1.pathId(), "/bin/1", v10, f1.fileId())
        trv.addFile(f2.pathId(), "/bin/2", v10, f2.fileId())
        trv.addFile(f3.pathId(), "/bin/3", v10, f3.fileId())
        trv.addFile(self.id4, "/bin/distributed", v10, self.fid4)
        trv.troveInfo.size.set(1234)
        trv.troveInfo.sourceName.set('somesource')

        req = deps.DependencySet()
        req.addDep(deps.FileDependencies, deps.Dependency("/bin/bash"))
        req.addDep(deps.TroveDependencies, deps.Dependency("foo:runtime"))
        req.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setRequires(req)

        # this also lets us peek at the database to make sure libtest.so.1
        # is only in the dep table once
        prv = deps.DependencySet()
        prv.addDep(deps.SonameDependencies, deps.Dependency("libtest.so.1"))
        trv.setProvides(prv)
        trv.computeDigests()

        store.db.transaction()
        store.addTroveSetStart([], dirSet, baseSet)
        troveInfo = store.addTrove(trv, trv.diff(None)[0])
        troveInfo.addFile(f1.pathId(), "/bin/1", f1.fileId(), v10,
                          fileStream = f1.freeze())
        troveInfo.addFile(f2.pathId(), "/bin/2", f2.fileId(), v10,
                          fileStream = f2.freeze())
        troveInfo.addFile(f3.pathId(), "/bin/3", f3.fileId(), v10,
                          fileStream = f3.freeze())
        troveInfo.addFile(self.id4, "/bin/distributed", self.fid4, v10)
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        store.db.commit()

        cu = store.db.cursor()
        cu.execute("SELECT count(*) FROM Dependencies WHERE "
                   "name = 'libtest.so.1'")
        self.assertEqual(cu.next(), (1,))

        # make sure the sha1s were stored
        cu.execute("""
        SELECT dirname, basename, sha1
        FROM TroveFiles
        JOIN FileStreams USING (streamId)
        JOIN FilePaths ON TroveFiles.filePathId = FilePaths.filePathId
        JOIN Dirnames ON FilePaths.dirnameId = Dirnames.dirnameId
        JOIN Basenames ON FilePaths.basenameId = Basenames.basenameId
        ORDER BY dirname,basename""")
        items = [(os.path.join(cu.frombinary(x[0]), cu.frombinary(x[1])),
            cu.frombinary(x[2])) for x in cu.fetchall()]
        self.assertEqual(items,
                             [ ("/bin/1", f1.contents.sha1()),
                               ("/bin/2", f2.contents.sha1()),
                               ("/bin/3", f3.contents.sha1()),
                               ("/bin/distributed", None) ])

        cl = changelog.ChangeLog("test", "*****@*****.**", "another log\n")

        fromRepos = store.getTrove("testcomp", v10, flavor, cl)
        self.assertEqual(fromRepos, trv)
        self.assertEqual(fromRepos.getVersion().timeStamps(),
                             trv.getVersion().timeStamps())
        self.assertEqual(fromRepos.getChangeLog(), trv.getChangeLog())

        self.assertEqual(
            [ x for x in store.getTrove("testcomp", v10, flavor,
                                        withFiles = False).iterFileList() ],
            [] )

        l = store.iterFilesInTrove("testcomp", v10, flavor, sortByPath = True)
        l = [ x for x in l ]
        self.assertEqual(l,
                             [ (f1.pathId(), "/bin/1", f1.fileId(), v10),
                               (f2.pathId(), "/bin/2", f2.fileId(), v10),
                               (f3.pathId(), "/bin/3", f3.fileId(), v10),
                               (self.id4, "/bin/distributed", self.fid4, v10)])

        cl = changelog.ChangeLog("test", "*****@*****.**", "log for testpkg\n")
        trv2 = trove.Trove("testpkg", v10, flavor, cl)
        trv2.addTrove(trv.getName(), v10, flavor)
        trv2.addTrove("weakref", v10, flavor, weakRef = True)
        trv2.computeDigests()
        store.addTroveSetStart([], dirSet, baseSet)
        troveInfo = store.addTrove(trv2, trv2.diff(None)[0])
        store.addTroveDone(troveInfo)
        store.addTroveSetDone()
        self.assertEqual(store.getTrove("testpkg", v10, flavor), trv2)
      
        self.assertEqual(
            [ x for x in store.iterTroves([ ("testcomp", v10, flavor),
                                            ("testpkg", v10, flavor ) ]) ],
            [trv, trv2] )
        self.assertEqual(
            [ x for x in store.iterTroves([ ("testpkg", v10, flavor ),
                                            ("testcomp", v10, flavor) ]) ],
            [trv2, trv] )
        self.assertEqual(
            [ x for x in store.iterTroves([ ("testpkg", v10, flavor),
                                            ("testpkg", v10, flavor) ]) ],
            [trv2, trv2] )
        self.assertEqual(
            [ x for x in store.iterTroves([ ("testpkg", v10, flavor ),
                                            ("blah", v10, flavor) ]) ],
            [trv2, None] )
        self.assertEqual(
            [ x for x in store.iterTroves([ ("blah", v10, flavor ),
                                            ("testpkg", v10, flavor) ]) ],
            [None, trv2] )
        self.assertEqual(
            [ x for x in store.iterTroves([ ("blah", v10, flavor ) ]) ],
            [None] )
        self.assertEqual(
            [ x for x in store.iterTroves([ ("testcomp", v10, flavor),
                                            ("blah", v10, flavor ),
                                            ("testpkg", v10, flavor ) ]) ],
            [trv, None, trv2] )

        # erasing doesn't work
        #store.eraseTrove("testcomp", v10, None)
        #store.commit()
        self.assertEqual(store.getTrove("testpkg", v10, flavor), trv2)
        
        map = { 'testpkg': [ v10 ]}
        flavors = store.getTroveFlavors(map)
        if flavor is not None:
            flavorStr = flavor.freeze()
        else:
            flavorStr = ''
        self.assertEqual(flavors, { 'testpkg': {v10: [flavorStr]}})

        map = { 'testpkg3': [ v10 ]}
        flavors = store.getTroveFlavors(map)
        self.assertEqual(flavors, { 'testpkg3': {v10: []}})

        # test getFiles
        fileObjs = store.getFiles([(f1.pathId(), f1.fileId()),
                                   (f2.pathId(), f2.fileId())])
        self.assertEqual(fileObjs[(f1.pathId(), f1.fileId())], f1)
        self.assertEqual(fileObjs[(f2.pathId(), f2.fileId())], f2)

        # test that asking for an invalid fileid/pathid pair results
        # in no entry for the (pathid, fileid) in the returned dict
        invalidPathId = md5FromString('9' * 32)
        invalidFileId = sha1FromString('9' * 40)
        fileObjs = store.getFiles([(invalidPathId, invalidFileId)])
        # make sure fileObjs is empty
        assert(not fileObjs)

        # test that asking for contents that have to come from
        # a different repository works - we should get None
        # back
        fileObjs = store.getFiles([(self.id4, self.fid4)])
        self.assertEqual(fileObjs, {(self.id4, self.fid4): None})