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())
def _getFileInfo(self, hostname, troveString, pathHash): repos = self.getRepos() name, version, flavor = self._getTuple(troveString) try: trv = repos.getTrove(name, version, flavor, withFiles=True) except errors.TroveNotFound: raise NotImplementedError pathHash = sha1helper.md5FromString(pathHash) for pathId, path, fileId, fileVersion in trv.iterFileList(): if pathHash == sha1helper.md5String(path): break else: raise NotImplementedError fileObj = repos.getFileVersion(pathId, fileId, fileVersion) return repos, path, fileVersion, fileObj
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))
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))
def testChangeSetFromFile(self): # ensure that absolute changesets that are read from disk # that contain config files write out changesets to a file # that do not change the file type to a diff. # set up a file with some contents cont = self.workDir + '/contents' f = open(cont, 'w') f.write('hello, world!\n') f.close() pathId = sha1helper.md5FromString('0' * 32) f = files.FileFromFilesystem(cont, pathId) f.flags.isConfig(1) # create an absolute changeset cs = changeset.ChangeSet() # add a pkg diff v = versions.VersionFromString('/localhost@rpl:devel/1.0-1-1', timeStamps=[1.000]) flavor = deps.parseFlavor('') t = trove.Trove('test', v, flavor, None) t.addFile(pathId, '/contents', v, f.fileId()) diff = t.diff(None, absolute=1)[0] cs.newTrove(diff) # add the file and file contents cs.addFile(None, f.fileId(), f.freeze()) cs.addFileContents(pathId, f.fileId(), changeset.ChangedFileTypes.file, filecontents.FromFilesystem(cont), f.flags.isConfig()) # write out the changeset cs.writeToFile(self.workDir + '/foo.ccs') # read it back in cs2 = changeset.ChangeSetFromFile(self.workDir + '/foo.ccs') # write it out again (there was a bug where all config files # became diffs) cs2.writeToFile(self.workDir + '/bar.ccs') # read it again cs3 = changeset.ChangeSetFromFile(self.workDir + '/bar.ccs') # verify that the file is a file, not a diff ctype, contents = cs3.getFileContents(pathId, f.fileId()) assert (ctype == changeset.ChangedFileTypes.file)
def testChangeSetFromFile(self): # ensure that absolute changesets that are read from disk # that contain config files write out changesets to a file # that do not change the file type to a diff. # set up a file with some contents cont = self.workDir + '/contents' f = open(cont, 'w') f.write('hello, world!\n') f.close() pathId = sha1helper.md5FromString('0' * 32) f = files.FileFromFilesystem(cont, pathId) f.flags.isConfig(1) # create an absolute changeset cs = changeset.ChangeSet() # add a pkg diff v = versions.VersionFromString('/localhost@rpl:devel/1.0-1-1', timeStamps = [1.000]) flavor = deps.parseFlavor('') t = trove.Trove('test', v, flavor, None) t.addFile(pathId, '/contents', v, f.fileId()) diff = t.diff(None, absolute = 1)[0] cs.newTrove(diff) # add the file and file contents cs.addFile(None, f.fileId(), f.freeze()) cs.addFileContents(pathId, f.fileId(), changeset.ChangedFileTypes.file, filecontents.FromFilesystem(cont), f.flags.isConfig()) # write out the changeset cs.writeToFile(self.workDir + '/foo.ccs') # read it back in cs2 = changeset.ChangeSetFromFile(self.workDir + '/foo.ccs') # write it out again (there was a bug where all config files # became diffs) cs2.writeToFile(self.workDir + '/bar.ccs') # read it again cs3 = changeset.ChangeSetFromFile(self.workDir + '/bar.ccs') # verify that the file is a file, not a diff ctype, contents = cs3.getFileContents(pathId, f.fileId()) assert(ctype == changeset.ChangedFileTypes.file)
class Database(testhelp.TestCase): id1 = md5FromString("00010001000100010001000100010001") id2 = md5FromString("00010001000100010001000100010002") def testFindTrove(self): db = database.Database(':memory:', ':memory:') self.assertEqual(db.getTransactionCounter(), 0) flavor = deps.parseFlavor('~readline,!foo') v10 = ThawVersion("/conary.rpath.com@test:trunk/10:1.2-10-1") f1 = files.FileFromFilesystem("/etc/passwd", self.id1) trv = trove.Trove("testcomp", v10, flavor, None) trv.addFile(self.id1, "/bin/1", v10, f1.fileId()) trvInfo = db.addTrove(trv) db.addTroveDone(trvInfo) f2 = files.FileFromFilesystem("/etc/group", self.id2) v20 = ThawVersion("/conary.rpath.com@local:blah/20:1.3-2-1") trv = trove.Trove("testcomp", v20, flavor, None) trv.addFile(self.id2, "/bin/2", v20, f2.fileId()) trvInfo = db.addTrove(trv) db.addTroveDone(trvInfo) tup = [('testcomp', v10, flavor)] tup2 = [('testcomp', v10, flavor), ('testcomp', v20, flavor)] assert (db.findTrove(None, ('testcomp', '1.2-10-1', None)) == tup) assert (db.findTrove(None, ('testcomp', '1.2', None)) == tup) assert (set(db.findTrove( None, ('testcomp', None, parseFlavor('!foo')))) == set(tup2)) assert (db.findTrove(None, ('testcomp', ':trunk', None)) == tup) assert (db.findTrove([Label('conary.rpath.com@test:foo')], ('testcomp', ':trunk', None)) == tup) assert (db.findTrove(None, ('testcomp', ':trunk', None)) == tup) assert (db.findTrove(None, ('testcomp', '@test:trunk', None)) == tup) assert (db.findTrove([Label('conary.rpath.com@blah:foo')], ('testcomp', '@test:trunk', None)) == tup) # Transaction counter changes upon commit self.assertEqual(db.getTransactionCounter(), 0) db.commit() self.assertEqual(db.getTransactionCounter(), 1) def testIntermediateDirNotWritable(self): # CNY-2405 d = tempfile.mkdtemp() try: os.mkdir(d + '/var', 0400) try: db = database.Database(d, '/var/lib/conarydb/conarydb') except database.OpenError, e: self.assertEqual( str(e), 'Unable to open database %s/var/lib/conarydb/conarydb: ' 'cannot create directory %s/var/lib' % (d, d)) finally: os.chmod(d + '/var', 0755) shutil.rmtree(d) def testRootIsNotDir(self): # CNY-814 fd, fn = tempfile.mkstemp() os.close(fd) try: f = open(fn, 'w') f.close() try: db = database.Database(fn, '/var/lib/conarydb/conarydb') except database.OpenError, e: self.assertEqual( str(e), 'Unable to open database %s/var/lib/conarydb/conarydb: ' '%s is not a directory' % (fn, fn)) finally: os.unlink(fn) d = tempfile.mkdtemp() f = open(d + '/var', 'w') f.close() try: f = open(fn, 'w') f.close() try: db = database.Database(d, '/var/lib/conarydb/conarydb') except database.OpenError, e: self.assertEqual( str(e), 'Unable to open database %s/var/lib/conarydb/conarydb: ' '%s/var is not a directory' % (d, d)) finally: shutil.rmtree(d) def testDbIsLocked(self): # CNY-1175 def fakeConnect(*args, **kw): raise dbstore.sqlerrors.DatabaseLocked('database is locked') d = tempfile.mkdtemp() oldconnect = dbstore.connect try: dbstore.connect = fakeConnect db = database.Database(d, '/var/lib/conarydb/conarydb') try: db.iterAllTroves() except errors.DatabaseLockedError, e: self.assertEqual( str(e), "The local database is locked. It is possible that a database journal file exists that needs to be rolled back, but you don't have write permission to the database." ) except: self.fail('unexpected exception') else: self.fail('expected exception not raised') finally:
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')
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() == [])
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 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})
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)
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())