def testChangeLogTable(self): # this only works under mysql because we violate foreign key # constraints nodeId (and if we fixed that, on versionId and itemId) db = self.getDB() if db.driver != "sqlite": raise SkipTestException, "this test requires sqlite" schema.createChangeLog(db) db.commit() clt = cltable.ChangeLogTable(db) first = clt.add(1, changelog.ChangeLog("name", "contact", "message\n")) second = clt.add( 2, changelog.ChangeLog("name2", "contact2", "message2\n")) assert (first != second)
def getCloneChangeLog(self, trv): if self.cfg.name is None or self.cfg.contact is None: raise ValueError, \ "name and contact information must be set for clone" message = self.defaultMessage cl = changelog.ChangeLog(self.cfg.name, self.cfg.contact, message) prompt = ('Please enter the clone message' ' for\n %s=%s.' % (trv.getName(), trv.getVersion())) if not message and not cl.getMessageFromUser(prompt=prompt): return None return cl
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 testGroupInfoRecipeCook2(self): groupInfoRecipe = """ class GroupInfoRecipe(UserGroupInfoRecipe, BaseRequiresRecipe): name = 'groupinfo' clearBuildReqs() version = '1' abstractBaseClass = 1 """ # if we don't re-direct this setting, we can't build self.cfg.baseClassDir = '/usr/share/conary/baseclasses' self.openRepository() client = self.getConaryClient() repos = client.getRepos() fileDict = {'groupinfo.recipe' : filetypes.RegularFile(contents = groupInfoRecipe, config = True)} chLog = changelog.ChangeLog(name = 'foo', contact = 'bar', message = 'test\n') cs = client.createSourceTrove('groupinfo:source', str(self.cfg.buildLabel), '1', fileDict, chLog) repos.commitChangeSet(cs) res = self.cookFromRepository('groupinfo:source', buildLabel = self.cfg.buildLabel, repos = repos, logBuild = True) self.assertEquals(res[0][0], 'groupinfo:recipe')
def testBadEditorVariable(self): def _tempStream(): fd, tempf = tempfile.mkstemp() os.unlink(tempf) return os.fdopen(fd, "w+") oldEditor = self._invalidChangeLogEditor() cl = changelog.ChangeLog('Test User', '*****@*****.**', 'nomsg\n') commitMsg = "Line 1\nLine2\nLine3\n" newStdin = _tempStream() newStdin.write(commitMsg) newStdin.write('.') newStdin.seek(0) oldStderr = sys.stderr newStderr = _tempStream() # Redirect stdout too - raw_input will print the prompt string oldStdout = sys.stdout newStdout = _tempStream() oldStdin = sys.stdin ret = None try: sys.stdin = newStdin sys.stdout = newStdout sys.stderr = newStderr ret = cl.getMessageFromUser(prompt="ggg") finally: sys.stdin = oldStdin sys.stdout = oldStdout sys.stderr = oldStderr if oldEditor: os.environ['EDITOR'] = oldEditor self.assertTrue(ret) self.assertEqual(cl.message(), commitMsg) expMsg = ("Error executing %s. Please set the EDITOR\n" "environment variable to a valid editor, or enter log message,\n" "terminated with single '.' (or CTRL+D to cancel)\n" % '/foo/bar') newStderr.seek(0) self.assertEqual(newStderr.read(), expMsg) # Now fail it - EOF instead of single dot newStdin.truncate(0) newStdin.write("Line1\n") newStdin.seek(0) newStderr.truncate(0) newStdout.truncate(0) oldEditor = self._invalidChangeLogEditor() ret = None try: sys.stdin = newStdin sys.stdout = newStdout sys.stderr = newStderr ret = cl.getMessageFromUser(prompt="ggg") finally: sys.stdin = oldStdin sys.stderr = oldStderr sys.stdout = oldStdout if oldEditor: os.environ['EDITOR'] = oldEditor self.assertFalse(ret)
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 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()