From a5cf1bc1d3e38ab32a20707d66b08f1bb0beae91 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 17 Oct 2009 20:13:02 +0200 Subject: Removed a few diff-related test cases that fail now as the respective method is missing - these tests have to be redone in test-diff module accordingly --- test/testlib/helper.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index b66d3eaa..c4c0f2ba 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -23,8 +23,32 @@ class ListProcessAdapter(object): """Allows to use lists as Process object as returned by SubProcess.Popen. Its tailored to work with the test system only""" + class Stream(object): + """Simple stream emulater meant to work only with tests""" + def __init__(self, data): + self.data = data + self.cur_iter = None + + def __iter__(self): + dat = self.data + if isinstance(dat, basestring): + dat = dat.splitlines() + if self.cur_iter is None: + self.cur_iter = iter(dat) + return self.cur_iter + + def read(self): + dat = self.data + if isinstance(dat, (tuple,list)): + dat = "\n".join(dat) + return dat + + def next(self): + if self.cur_iter is None: + self.cur_iter = iter(self) + return self.cur_iter.next() + + # END stream + def __init__(self, input_list_or_string): - l = input_list_or_string - if isinstance(l,basestring): - l = l.splitlines() - self.stdout = iter(l) + self.stdout = self.Stream(input_list_or_string) -- cgit v1.2.3 From 9840afda82fafcc3eaf52351c64e2cfdb8962397 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 17:09:13 +0200 Subject: diff method now checks for git-diff errrs that can easily occour if the repository is bare and if there is no index or second tree specified --- test/testlib/helper.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index c4c0f2ba..b34c9303 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -52,3 +52,9 @@ class ListProcessAdapter(object): def __init__(self, input_list_or_string): self.stdout = self.Stream(input_list_or_string) + self.stderr = self.Stream('') + + def wait(self): + return 0 + + poll = wait -- cgit v1.2.3 From bb0ac304431e8aed686a8a817aaccd74b1ba4f24 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 15:04:29 +0200 Subject: Added frame for new Repo handling and some neat decorators, including tests that test whether the testing framework does what it should --- test/testlib/__init__.py | 1 - test/testlib/helper.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) (limited to 'test/testlib') diff --git a/test/testlib/__init__.py b/test/testlib/__init__.py index f364171b..2133eb8c 100644 --- a/test/testlib/__init__.py +++ b/test/testlib/__init__.py @@ -8,7 +8,6 @@ import inspect from mock import * from asserts import * from helper import * -from unittest import TestCase __all__ = [ name for name, obj in locals().items() if not (name.startswith('_') or inspect.ismodule(obj)) ] diff --git a/test/testlib/helper.py b/test/testlib/helper.py index b34c9303..bc314cb2 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -5,6 +5,8 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import os +from git import Repo +from unittest import TestCase GIT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -58,3 +60,99 @@ class ListProcessAdapter(object): return 0 poll = wait + + +def with_bare_rw_repo(func): + """ + Decorator providing a specially made read-write repository to the test case + decorated with it. The test case requires the following signature:: + def case(self, rw_repo) + + The rwrepo will be a bare clone or the types rorepo. Once the method finishes, + it will be removed completely. + + Use this if you want to make purely index based adjustments, change refs, create + heads, generally operations that do not need a working tree. + """ + def bare_repo_creator(self): + rw_repo = None + try: + return func(self, rw_repo) + finally: + pass + # END cleanup + # END bare repo creator + bare_repo_creator.__name__ = func.__name__ + return bare_repo_creator + +def with_rw_repo(func, working_tree_ref='0.1.6'): + """ + Same as with_bare_repo, but clones the rorepo as non-bare repository, checking + out the working tree at the given working_tree_ref. + + This repository type is more costly due to the working copy checkout. + """ + def repo_creator(self): + rw_repo = None + try: + return func(self, rw_repo) + finally: + pass + # END cleanup + # END bare repo creator + repo_creator.__name__ = func.__name__ + return repo_creator + +def with_rw_and_rw_remote_repo(func): + """ + Same as with_rw_repo, but also provides a writable remote repository from which the + rw_repo has been forked. The remote repository was cloned as bare repository from + the rorepo, wheras the rw repo has a working tree and was cloned from the remote repository. + + The following scetch demonstrates this:: + rorepo ------> rw_remote_repo ------> rw_repo + + The test case needs to support the following signature:: + def case(self, rw_repo, rw_remote_repo) + + This setup allows you to test push and pull scenarios and hooks nicely. + """ + def remote_repo_creator(self): + rw_repo = None + rw_remote_repo = None + try: + return func(self, rw_repo, rw_remote_repo) + finally: + pass + # END cleanup + # END bare repo creator + remote_repo_creator.__name__ = func.__name__ + return remote_repo_creator + + +class TestBase(TestCase): + """ + Base Class providing default functionality to all tests such as: + + - Utility functions provided by the TestCase base of the unittest method such as:: + self.fail("todo") + self.failUnlessRaises(...) + + - Class level repository which is considered read-only as it is shared among + all test cases in your type. + Access it using:: + self.rorepo # 'ro' stands for read-only + + The rorepo is in fact your current project's git repo. If you refer to specific + shas for your objects, be sure you choose some that are part of the immutable portion + of the project history ( to assure tests don't fail for others ). + """ + + @classmethod + def setUpAll(cls): + """ + Dynamically add a read-only repository to our actual type. This way + each test type has its own repository + """ + cls.rorepo = Repo(GIT_REPO) + -- cgit v1.2.3 From 9c3bbc43d097656b54c808290ce0c656d127ce47 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 15:36:41 +0200 Subject: Implemented decorators, tests pass at least --- test/testlib/helper.py | 70 +++++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 26 deletions(-) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index bc314cb2..c4fccbf6 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -7,6 +7,8 @@ import os from git import Repo from unittest import TestCase +import tempfile +import shutil GIT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -75,35 +77,41 @@ def with_bare_rw_repo(func): heads, generally operations that do not need a working tree. """ def bare_repo_creator(self): - rw_repo = None + repo_dir = tempfile.mktemp("bare_repo") + rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=True) try: return func(self, rw_repo) finally: - pass + shutil.rmtree(repo_dir) # END cleanup # END bare repo creator bare_repo_creator.__name__ = func.__name__ return bare_repo_creator -def with_rw_repo(func, working_tree_ref='0.1.6'): +def with_rw_repo(working_tree_ref='0.1.6'): """ Same as with_bare_repo, but clones the rorepo as non-bare repository, checking out the working tree at the given working_tree_ref. This repository type is more costly due to the working copy checkout. """ - def repo_creator(self): - rw_repo = None - try: - return func(self, rw_repo) - finally: - pass - # END cleanup - # END bare repo creator - repo_creator.__name__ = func.__name__ - return repo_creator - -def with_rw_and_rw_remote_repo(func): + def argument_passer(func): + def repo_creator(self): + repo_dir = tempfile.mktemp("non_bare_repo") + rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=False, n=True) + rw_repo.git.checkout(working_tree_ref) + try: + return func(self, rw_repo) + finally: + shutil.rmtree(repo_dir) + # END cleanup + # END rw repo creator + repo_creator.__name__ = func.__name__ + return repo_creator + # END argument passer + return argument_passer + +def with_rw_and_rw_remote_repo(working_tree_ref='0.1.6'): """ Same as with_rw_repo, but also provides a writable remote repository from which the rw_repo has been forked. The remote repository was cloned as bare repository from @@ -117,17 +125,27 @@ def with_rw_and_rw_remote_repo(func): This setup allows you to test push and pull scenarios and hooks nicely. """ - def remote_repo_creator(self): - rw_repo = None - rw_remote_repo = None - try: - return func(self, rw_repo, rw_remote_repo) - finally: - pass - # END cleanup - # END bare repo creator - remote_repo_creator.__name__ = func.__name__ - return remote_repo_creator + def argument_passer(func): + def remote_repo_creator(self): + remote_repo_dir = tempfile.mktemp("remote_repo") + repo_dir = tempfile.mktemp("remote_clone_non_bare_repo") + + rw_remote_repo = self.rorepo.clone(remote_repo_dir, shared=True, bare=True) + rw_repo = rw_remote_repo.clone(repo_dir, shared=True, bare=False, n=True) # recursive alternates info ? + rw_repo.git.checkout(working_tree_ref) + try: + return func(self, rw_repo, rw_remote_repo) + finally: + shutil.rmtree(repo_dir) + shutil.rmtree(remote_repo_dir) + # END cleanup + # END bare repo creator + remote_repo_creator.__name__ = func.__name__ + return remote_repo_creator + # END remote repo creator + # END argument parsser + + return argument_passer class TestBase(TestCase): -- cgit v1.2.3 From 3c770f8e98a0079497d3eb5bc31e7260cc70cc63 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 16:06:10 +0200 Subject: Fixed decorator issue that would cause a function to be passed even though there is a default argument. This feels inconsistent as the 'argument passer' wrapper function can be called with a function or a string as first argument depending on whether the client code was explicitly passing an argument or not. That ... sucks. Now test for that case specifically and fail with a proper assertion error. I don't like it, but what can I do ... . Remote tests adjusted to use rw repositories instead. More tests to follow, and many api methods are to be implemented now these things can be tested properly. --- test/testlib/helper.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index c4fccbf6..eef7876f 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -88,13 +88,14 @@ def with_bare_rw_repo(func): bare_repo_creator.__name__ = func.__name__ return bare_repo_creator -def with_rw_repo(working_tree_ref='0.1.6'): +def with_rw_repo(working_tree_ref): """ Same as with_bare_repo, but clones the rorepo as non-bare repository, checking out the working tree at the given working_tree_ref. This repository type is more costly due to the working copy checkout. """ + assert isinstance(working_tree_ref, basestring), "Decorator requires ref name for working tree checkout" def argument_passer(func): def repo_creator(self): repo_dir = tempfile.mktemp("non_bare_repo") @@ -111,7 +112,7 @@ def with_rw_repo(working_tree_ref='0.1.6'): # END argument passer return argument_passer -def with_rw_and_rw_remote_repo(working_tree_ref='0.1.6'): +def with_rw_and_rw_remote_repo(working_tree_ref): """ Same as with_rw_repo, but also provides a writable remote repository from which the rw_repo has been forked. The remote repository was cloned as bare repository from @@ -125,6 +126,7 @@ def with_rw_and_rw_remote_repo(working_tree_ref='0.1.6'): This setup allows you to test push and pull scenarios and hooks nicely. """ + assert isinstance(working_tree_ref, basestring), "Decorator requires ref name for working tree checkout" def argument_passer(func): def remote_repo_creator(self): remote_repo_dir = tempfile.mktemp("remote_repo") -- cgit v1.2.3 From 20c34a929a8b2871edd4fd44a38688e8977a4be6 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 17:40:04 +0200 Subject: =?UTF-8?q?Added=20reset=20method=20to=20Head=20-=20its=20a=20clas?= =?UTF-8?q?s=20method=20due=20to=20the=20very=20general=20nature=20of=20th?= =?UTF-8?q?e=20command.=20Yet=20I=20don't=20really=20like=20the=20way=20yo?= =?UTF-8?q?u=20have=20to=20call=20it=20as=20repo=20has=20to=20be=20?= =?UTF-8?q?=E1=B9=95assed=20as=20first=20arg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/testlib/helper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index eef7876f..ab4b9f4e 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -100,7 +100,7 @@ def with_rw_repo(working_tree_ref): def repo_creator(self): repo_dir = tempfile.mktemp("non_bare_repo") rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=False, n=True) - rw_repo.git.checkout(working_tree_ref) + rw_repo.git.checkout("-b", "master", working_tree_ref) try: return func(self, rw_repo) finally: @@ -134,7 +134,7 @@ def with_rw_and_rw_remote_repo(working_tree_ref): rw_remote_repo = self.rorepo.clone(remote_repo_dir, shared=True, bare=True) rw_repo = rw_remote_repo.clone(repo_dir, shared=True, bare=False, n=True) # recursive alternates info ? - rw_repo.git.checkout(working_tree_ref) + rw_repo.git.checkout("-b", "master", working_tree_ref) try: return func(self, rw_repo, rw_remote_repo) finally: -- cgit v1.2.3 From 22757ed7b58862cccef64fdc09f93ea1ac72b1d2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 11:58:20 +0100 Subject: put _make_file helper method into TestBase class remote: prepared FetchInfo class to be returned by fetch and pull. About to implement tests --- test/testlib/helper.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index ab4b9f4e..d541a111 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -175,4 +175,15 @@ class TestBase(TestCase): each test type has its own repository """ cls.rorepo = Repo(GIT_REPO) - + + def _make_file(self, rela_path, data, repo=None): + """ + Create a file at the given path relative to our repository, filled + with the given data. Returns absolute path to created file. + """ + repo = repo or self.rorepo + abs_path = os.path.join(repo.git.git_dir, rela_path) + fp = open(abs_path, "w") + fp.write(data) + fp.close() + return abs_path -- cgit v1.2.3 From a519942a295cc39af4eebb7ba74b184decae13fb Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 18:09:18 +0100 Subject: Tried to use shallow repository - this works in case it is remote, but unfortunately, deepening the repository fails if the server is used. This is bad, but a workaround is to create another shared repo which pushes a changes that we fetch into our given repo. This should provide more output to properly test the fetch handling. Harder than I thought --- test/testlib/helper.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'test/testlib') diff --git a/test/testlib/helper.py b/test/testlib/helper.py index d541a111..081299be 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -5,7 +5,7 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import os -from git import Repo +from git import Repo, Remote from unittest import TestCase import tempfile import shutil @@ -115,8 +115,15 @@ def with_rw_repo(working_tree_ref): def with_rw_and_rw_remote_repo(working_tree_ref): """ Same as with_rw_repo, but also provides a writable remote repository from which the - rw_repo has been forked. The remote repository was cloned as bare repository from - the rorepo, wheras the rw repo has a working tree and was cloned from the remote repository. + rw_repo has been forked as well as a handle for a git-daemon that may be started to + run the remote_repo. + The remote repository was cloned as bare repository from the rorepo, wheras + the rw repo has a working tree and was cloned from the remote repository. + + remote_repo has two remotes: origin and daemon_origin. One uses a local url, + the other uses a server url. The daemon setup must be done on system level + and should be an inetd service that serves tempdir.gettempdir() and all + directories in it. The following scetch demonstrates this:: rorepo ------> rw_remote_repo ------> rw_repo @@ -135,6 +142,28 @@ def with_rw_and_rw_remote_repo(working_tree_ref): rw_remote_repo = self.rorepo.clone(remote_repo_dir, shared=True, bare=True) rw_repo = rw_remote_repo.clone(repo_dir, shared=True, bare=False, n=True) # recursive alternates info ? rw_repo.git.checkout("-b", "master", working_tree_ref) + + # prepare for git-daemon + rw_remote_repo.daemon_export = True + + # this thing is just annoying ! + crw = rw_remote_repo.config_writer() + section = "daemon" + try: + crw.add_section(section) + except Exception: + pass + crw.set(section, "receivepack", True) + # release lock + del(crw) + + # initialize the remote - first do it as local remote and pull, then + # we change the url to point to the daemon. The daemon should be started + # by the user, not by us + d_remote = Remote.create(rw_repo, "daemon_origin", remote_repo_dir) + d_remote.fetch() + d_remote.config_writer.set('url', "git://localhost%s" % remote_repo_dir) + try: return func(self, rw_repo, rw_remote_repo) finally: -- cgit v1.2.3