diff --git a/osc/core.py b/osc/core.py index 4113d8e7..316d9a7e 100644 --- a/osc/core.py +++ b/osc/core.py @@ -1042,8 +1042,9 @@ class Package: if self.islink() and self.isexpanded(): self.update_local_filesmeta(revision=self.latest_rev()) else: - self.update_local_filesmeta() + self.update_local_filesmeta(self.rev) self.write_deletelist() + self.write_addlist() self.update_datastructs() for filename in todo_delete: diff --git a/tests/common.py b/tests/common.py index 5c18a3b4..69377f54 100644 --- a/tests/common.py +++ b/tests/common.py @@ -6,10 +6,11 @@ import shutil import tempfile import os import sys +from xml.etree import cElementTree as ET EXPECTED_REQUESTS = [] class RequestWrongOrder(Exception): - """issued if an unexpected request is issued to urllib2""" + """raised if an unexpected request is issued to urllib2""" def __init__(self, url, exp_url, method, exp_method): Exception.__init__(self) self.url = url @@ -20,6 +21,16 @@ class RequestWrongOrder(Exception): def __str__(self): return '%s, %s, %s, %s' % (self.url, self.exp_url, self.method, self.exp_method) +class RequestDataMismatch(Exception): + """raised if POSTed or PUTed data doesn't match with the expected data""" + def __init__(self, url, got, exp): + self.url = url + self.got = got + self.exp = exp + + def __str__(self): + return '%s, %s, %s' % (self.url, self.got, self.exp) + class MyHTTPHandler(urllib2.HTTPHandler): def __init__(self, exp_requests, fixtures_dir): urllib2.HTTPHandler.__init__(self) @@ -28,16 +39,31 @@ class MyHTTPHandler(urllib2.HTTPHandler): def http_open(self, req): r = self.__exp_requests.pop(0) - if req.get_full_url() != r[1] and req.get_method() == r[0]: + if req.get_full_url() != r[1] or req.get_method() != r[0]: raise RequestWrongOrder(req.get_full_url(), r[1], req.get_method(), r[0]) - if req.get_method() == 'GET': + if req.get_method() in ('GET', 'DELETE'): return self.__mock_GET(r[1], **r[2]) + elif req.get_method() in ('PUT', 'POST'): + return self.__mock_PUT(req, **r[2]) def __mock_GET(self, fullurl, **kwargs): return self.__get_response(fullurl, **kwargs) + def __mock_PUT(self, req, **kwargs): + exp = kwargs.get('exp', None) + if exp is not None and kwargs.has_key('expfile'): + raise RuntimeError('either specify exp or expfile') + elif kwargs.has_key('expfile'): + exp = open(os.path.join(self.__fixtures_dir, kwargs['expfile']), 'r').read() + if exp is not None: + if req.get_data() != exp: + raise RequestDataMismatch(req.get_full_url(), req.get_data(), exp) + return self.__get_response(req.get_full_url(), **kwargs) + def __get_response(self, url, **kwargs): f = None + if kwargs.has_key('exception'): + raise kwargs['exception'] if not kwargs.has_key('text') and kwargs.has_key('file'): f = StringIO.StringIO(open(os.path.join(self.__fixtures_dir, kwargs['file']), 'r').read()) elif kwargs.has_key('text') and not kwargs.has_key('file'): @@ -49,10 +75,10 @@ class MyHTTPHandler(urllib2.HTTPHandler): resp.msg = '' return resp -def GET(fullurl, **kwargs): +def urldecorator(method, fullurl, **kwargs): def decorate(test_method): def wrapped_test_method(*args): - addExpectedRequest('GET', fullurl, **kwargs) + addExpectedRequest(method, fullurl, **kwargs) test_method(*args) # "rename" method otherwise we cannot specify a TestCaseClass.testName # cmdline arg when using unittest.main() @@ -60,6 +86,18 @@ def GET(fullurl, **kwargs): return wrapped_test_method return decorate +def GET(fullurl, **kwargs): + return urldecorator('GET', fullurl, **kwargs) + +def PUT(fullurl, **kwargs): + return urldecorator('PUT', fullurl, **kwargs) + +def POST(fullurl, **kwargs): + return urldecorator('POST', fullurl, **kwargs) + +def DELETE(fullurl, **kwargs): + return urldecorator('DELETE', fullurl, **kwargs) + def addExpectedRequest(method, url, **kwargs): global EXPECTED_REQUESTS EXPECTED_REQUESTS.append((method, url, kwargs)) @@ -105,3 +143,13 @@ class OscTestCase(unittest.TestCase): def _check_status(self, p, fname, exp): self.assertEqual(p.status(fname), exp) + + def _check_digests(self, fname, *skipfiles): + fname = os.path.join(self._get_fixtures_dir(), fname) + self.assertEqual(open(os.path.join('.osc', '_files'), 'r').read(), open(fname, 'r').read()) + root = ET.parse(fname).getroot() + for i in root.findall('entry'): + if i.get('name') in skipfiles: + continue + self.assertTrue(os.path.exists(os.path.join('.osc', i.get('name')))) + self.assertEqual(osc.core.dgst(os.path.join('.osc', i.get('name'))), i.get('md5')) diff --git a/tests/suite.py b/tests/suite.py index 866f1f85..673f62af 100644 --- a/tests/suite.py +++ b/tests/suite.py @@ -5,6 +5,7 @@ import test_deletefiles import test_revertfiles import test_difffiles import test_init_package +import test_commit suite = unittest.TestSuite() suite.addTests(test_addfiles.suite()) @@ -13,4 +14,5 @@ suite.addTests(test_revertfiles.suite()) suite.addTests(test_update.suite()) suite.addTests(test_difffiles.suite()) suite.addTests(test_init_package.suite()) +suite.addTests(test_commit.suite()) unittest.TextTestRunner(verbosity=1).run(suite) diff --git a/tests/test_update.py b/tests/test_update.py index 718b0f2e..b08f11e3 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -3,7 +3,6 @@ import osc.oscerr import os import sys from common import GET, OscTestCase -from xml.etree import cElementTree as ET FIXTURES_DIR = os.path.join(os.getcwd(), 'update_fixtures') def suite(): @@ -31,7 +30,7 @@ class TestUpdate(OscTestCase): osc.core.Package('.').update(rev=2) exp = 'A upstream_added\nAt revision 2.\n' self.assertEqual(sys.stdout.getvalue(), exp) - self.__check_digests('testUpdateNewFile_files') + self._check_digests('testUpdateNewFile_files') @GET('http://localhost/source/osctest/simple?rev=2', file='testUpdateNewFileLocalExists_files') def testUpdateNewFileLocalExists(self): @@ -50,7 +49,7 @@ class TestUpdate(OscTestCase): osc.core.Package('.').update(rev=2) exp = 'D foo\nAt revision 2.\n' self.assertEqual(sys.stdout.getvalue(), exp) - self.__check_digests('testUpdateDeletedFile_files') + self._check_digests('testUpdateDeletedFile_files') self.assertFalse(os.path.exists('foo')) self.assertFalse(os.path.exists(os.path.join('.osc', 'foo'))) @@ -64,7 +63,7 @@ class TestUpdate(OscTestCase): osc.core.Package('.').update(rev=2) exp = 'U foo\nAt revision 2.\n' self.assertEqual(sys.stdout.getvalue(), exp) - self.__check_digests('testUpdateUpstreamModifiedFile_files') + self._check_digests('testUpdateUpstreamModifiedFile_files') @GET('http://localhost/source/osctest/conflict?rev=2', file='testUpdateConflict_files') @GET('http://localhost/source/osctest/conflict/merge?rev=2', file='testUpdateConflict_merge') @@ -77,7 +76,7 @@ class TestUpdate(OscTestCase): self._change_to_pkg('conflict') osc.core.Package('.').update(rev=2) exp = 'C merge\nAt revision 2.\n' - self.__check_digests('testUpdateConflict_files') + self._check_digests('testUpdateConflict_files') self.assertEqual(sys.stdout.getvalue(), exp) self._check_conflictlist('merge\n') @@ -93,7 +92,7 @@ class TestUpdate(OscTestCase): exp = 'skipping \'merge\' (this is due to conflicts)\nAt revision 2.\n' self.assertEqual(sys.stdout.getvalue(), exp) self._check_conflictlist('merge\n') - self.__check_digests('testUpdateAlreadyInConflict_files') + self._check_digests('testUpdateAlreadyInConflict_files') @GET('http://localhost/source/osctest/deleted?rev=2', file='testUpdateLocalDeletions_files') @GET('http://localhost/source/osctest/deleted/foo?rev=2', file='testUpdateLocalDeletions_foo') @@ -113,7 +112,7 @@ class TestUpdate(OscTestCase): self._check_deletelist('foo\n') self._check_conflictlist('merge\n') self.assertEqual(open('foo', 'r').read(), open(os.path.join('.osc', 'foo'), 'r').read()) - self.__check_digests('testUpdateLocalDeletions_files') + self._check_digests('testUpdateLocalDeletions_files') @GET('http://localhost/source/osctest/restore?rev=latest', file='testUpdateRestore_files') @GET('http://localhost/source/osctest/restore/foo?rev=1', file='testUpdateRestore_foo') @@ -124,7 +123,7 @@ class TestUpdate(OscTestCase): osc.core.Package('.').update() exp = 'Restored \'foo\'\nAt revision 1.\n' self.assertEqual(sys.stdout.getvalue(), exp) - self.__check_digests('testUpdateRestore_files') + self._check_digests('testUpdateRestore_files') @GET('http://localhost/source/osctest/limitsize?rev=latest', file='testUpdateLimitSizeNoChange_filesremote') @GET('http://localhost/source/osctest/limitsize/_meta', file='meta.xml') @@ -139,7 +138,7 @@ class TestUpdate(OscTestCase): self.assertEqual(sys.stdout.getvalue(), exp) self.assertFalse(os.path.exists(os.path.join('.osc', 'bigfile'))) self.assertFalse(os.path.exists('bigfile')) - self.__check_digests('testUpdateLimitSizeNoChange_files', 'bigfile') + self._check_digests('testUpdateLimitSizeNoChange_files', 'bigfile') @GET('http://localhost/source/osctest/limitsize?rev=latest', file='testUpdateLimitSizeAddDelete_filesremote') @GET('http://localhost/source/osctest/limitsize/exists?rev=2', file='testUpdateLimitSizeAddDelete_exists') @@ -165,7 +164,7 @@ class TestUpdate(OscTestCase): # exists because local version is modified self.assertTrue(os.path.exists('nochange')) - self.__check_digests('testUpdateLimitSizeAddDelete_files', 'bigfile', 'foo', 'merge', 'nochange') + self._check_digests('testUpdateLimitSizeAddDelete_files', 'bigfile', 'foo', 'merge', 'nochange') @GET('http://localhost/source/osctest/services?rev=latest', file='testUpdateServiceFilesAddDelete_filesremote') @GET('http://localhost/source/osctest/services/bigfile?rev=2', file='testUpdateServiceFilesAddDelete_bigfile') @@ -188,7 +187,7 @@ class TestUpdate(OscTestCase): self.assertTrue(os.path.exists('_service:foo')) self.assertEqual(open('_service:foo').read(), 'small\n') self.assertTrue(os.path.exists('_service:exists')) - self.__check_digests('testUpdateServiceFilesAddDelete_files', '_service:foo', '_service:bar') + self._check_digests('testUpdateServiceFilesAddDelete_files', '_service:foo', '_service:bar') # tests to recover from an aborted/broken update @@ -204,7 +203,7 @@ class TestUpdate(OscTestCase): exp = 'resuming broken update...\nU foo\nU merge\nAt revision 2.\nAt revision 2.\n' self.assertEqual(sys.stdout.getvalue(), exp) self.assertFalse(os.path.exists(os.path.join('.osc', '_in_update'))) - self.__check_digests('testUpdateResume_files') + self._check_digests('testUpdateResume_files') @GET('http://localhost/source/osctest/simple/added?rev=1', file='testUpdateResumeDeletedFile_foo') @GET('http://localhost/source/osctest/simple/foo?rev=1', file='testUpdateResumeDeletedFile_foo') @@ -225,17 +224,7 @@ class TestUpdate(OscTestCase): self.assertFalse(os.path.exists(os.path.join('.osc', '_in_update'))) self.assertFalse(os.path.exists('added')) self.assertFalse(os.path.exists(os.path.join('.osc', 'added'))) - self.__check_digests('testUpdateResumeDeletedFile_files') - - def __check_digests(self, fname, *skipfiles): - fname = os.path.join(self._get_fixtures_dir(), fname) - self.assertEqual(open(os.path.join('.osc', '_files'), 'r').read(), open(fname, 'r').read()) - root = ET.parse(fname).getroot() - for i in root.findall('entry'): - if i.get('name') in skipfiles: - continue - self.assertTrue(os.path.exists(os.path.join('.osc', i.get('name')))) - self.assertEqual(osc.core.dgst(os.path.join('.osc', i.get('name'))), i.get('md5')) + self._check_digests('testUpdateResumeDeletedFile_files') if __name__ == '__main__': import unittest