Ejemplo n.º 1
0
def sync_batch(git_couchdb_url, design_couchdb_url, branch, app_subdir):
    if branch is None:
        branches = [
            b["_id"] for b in get(
                posixpath.join(git_couchdb_url, "git-branches"))["branches"]]
    else:
        # TODO: Should really look for branches with this name using
        # an index
        branches = ["git-branch-" + branch]
    with mkdtemp() as temp_dir:
        for branch in branches:
            basename = urllib.quote(branch, safe="")
            local_dir = os.path.join(temp_dir, basename)
            commit = get(posixpath.join(git_couchdb_url, 
                                        branch))["commit"]["_id"]
            tree = get(posixpath.join(git_couchdb_url, 
                                      commit))["tree"]["_id"]
            if app_subdir != ".":
                # TODO: Support multi-level sub_dir
                assert "/" not in app_subdir, app_subdir
                for child in get(posixpath.join(git_couchdb_url, 
                                                tree))["children"]:
                    if child["basename"] == app_subdir:
                        assert child["child"]["type"] == "git-tree", child
                        tree = child["child"]["_id"]
                        break
                else:
                    raise Exception("Missing child %r" % (app_subdir,))
            doc_url = posixpath.join(design_couchdb_url, 
                                     "_design", url_quote(basename))
            existing = get(doc_url)
            if existing.get("couchapp_git_tree_id") == tree:
                continue
            print "Updating %r..." % (branch,)
            tree_to_fs(git_couchdb_url, local_dir, tree)
            write_file(os.path.join(local_dir, "couchapp_git_tree_id"),
                       tree)
            if os.path.exists(os.path.join(local_dir, "_id")):
                os.unlink(os.path.join(local_dir, "_id"))
            couchapp(doc_url, local_dir)
            print "...done %r" % (branch,)            
Ejemplo n.º 2
0
    def test(self):
        # Clean up any partially aborted test runs
        def mark_aborted(doc):
            doc.update({"status": "aborted"})
        queue_url = posixpath.join(self.couchdb_url, "test-queue")
        queued_ids = set(i["_id"] for i in get(queue_url)["queue"])
        pending_map_func = """\
function (doc) {
  var prefix = "test-run-";
  if (doc._id.substr(0, prefix.length) == prefix) {
    if (doc.status == "pending") {
      emit(null, doc._id);
    }
  }
}
"""
        git_map_func = """\
function (doc) {
  var prefix  = "test-";
  if (doc._id.substr(0, prefix.length) != prefix) {
    emit(null, doc._id);
  }
}
"""
        design_doc = {
            "language": "javascript",
            "views": {
                "pending-tests": {
                    "map": pending_map_func,
                    }, 
                "git-documents": {
                    "map": git_map_func,
                    },
                },
            }
        put_update(posixpath.join(self.couchdb_url, "_design/test"),
                   lambda a=None: design_doc)
        result = get(posixpath.join(self.couchdb_url, 
                                    "_design/test/_view/pending-tests"))
        pending_ids = set(i["id"] for i in result["rows"])
        for missing_id in pending_ids - queued_ids:
            put_update(posixpath.join(self.couchdb_url, url_quote(missing_id)),
                       mark_aborted)
        # Add this test run to the queue on the shared database
        def now():
            return datetime.datetime.utcnow().isoformat() + "Z"
        document = {
            "request_time": now(),
            "start_time": "",
            "end_time": "",
            "status": "pending",
            }
        result = post_new(self.couchdb_url, document, 
                          id_template="test-run-%s")
        my_url = posixpath.join(self.couchdb_url, url_quote(result["id"]))
        def append_to_queue(queued):
            queued.setdefault("queue", []).append(
                {"_id": result["id"],
                 "request_time": document["request_time"],
                 })
        def remove_from_queue(queued):
            queue = queued.get("queue", [])
            queue = [e for e in queue if e.get("_id") != result["id"]]
            queued["queue"] = queue
        put_update(queue_url, append_to_queue)
        try:
            while True:
                queue = get(queue_url)
                for i, entry in enumerate(queue.get("queue", [])):
                    if entry["_id"] == result["id"]:
                        my_index = i
                        break
                else:
                    raise Exception("I seem to have been un queued")
        # Is there a non-expired entry in the queue ahead of mine?
                if my_index == 0:
                    def mark_running(job):
                        job.update(
                            {"status": "running",
                             "start_time": now()})
                    status = "aborted"
                    def mark_stopped(job):
                        job.update(
                            {"status": status,
                             "stop_time": now()})
        # Mark the test as running 
                    put_update(my_url, mark_running)
                    try:
                        try:
                            self._run_test()
                        except AssertionError:
                            status = "failed"
                            raise
                        except Exception:
                            status = "error"
                            raise
                        else:
                            status = "passed"
                            return
                    finally:
                        put_update(my_url, mark_stopped)
                else:
        # Set a timout for the next time to check, if necessary
                    print "sleeping..."
                    time.sleep(5)
        finally:
        # Mark the test as completed
            put_update(queue_url, remove_from_queue)
Ejemplo n.º 3
0
    def _run_test(self):
        # Wipe out all git-related documents and the design document
        result = get(posixpath.join(self.couchdb_url, 
                                    "_design/test/_view/git-documents"))
        for item in result["rows"]:
            delete(posixpath.join(self.couchdb_url, url_quote(item["id"])))
        # Upload the gitbrowser to the couchdb design document
        gitbrowser_source_path = os.path.join(self.source_path, "gitbrowser")
        couchapp(posixpath.join(self.couchdb_url, "_design/gitbrowser"), 
                 gitbrowser_source_path)
        # Populate a test GIT repository
        with mkdtemp() as temp_dir:
            cwd_script = ["bash", "-c", 'cd "$1" && shift && exec "$@"', "-", 
                          temp_dir]
            subprocess.check_call(cwd_script + ["git", "init"])
        ## write file README
            git = cwd_script + ["env", 
                                "HOME=%s" % (temp_dir,),
                                "git"]
            subprocess.check_call(git + ["config", "user.name", "Tester"])
            subprocess.check_call(git + ["config", "user.email", 
                                         "*****@*****.**"])
            path = os.path.join(temp_dir, "README")
            with open(path, "wb") as fh:
                fh.write("Initial version of text file\r\n")
            subprocess.check_call(git + ["add", path])
            subprocess.check_call(git + ["commit", "-m", 
                                         "Initial commit"])
        ## write file README
            with open(path, "wb") as fh:
                fh.write("""\
# Purpose

This is a minimal git repository for testing

# Example Markdown

Readme files like this are Markdown formatted:

 * Bullet points
 * Headings
 * Code blocks
 * _etc_

They can have hyperlinks:

 * to other hosts like [google](http://www.google.com/)
 * absolute paths, like the [hexdump file](/show/master/head/binary-file)
 * relative paths, like the [child folder](subfolder)

""")
            subprocess.check_call(git + ["add", path])
        ## write file binary 
            path = os.path.join(temp_dir, "binary-file")
            with open(path, "wb") as fh:
                fh.write("".join(chr(i) for i in range(2**8)))
            subprocess.check_call(git + ["add", path])
        ## write python file 
            path = os.path.join(temp_dir, "example.py")
            with open(path, "wb") as fh:
                fh.write("""\
## Example\r\n\
#This is an example python file\r\n\
#\r\n\
#  - Example bullet list\r\n\
#  - _etc_\r\n\
#\r\n\
#Because of the blank line, this documentation block should not\r\n\
#have any code on the right and the following code block should not\r\n\
#have any documentation to its left.\r\n\
\r\n\
from __future__ import division\r\n\
import os, sys, unittest\r\n\
\r\n\
class SomeTest(unittest.TestCase):\r\n\
\r\n\
  def testSomething(self):\r\n\
    '''Just an example test'''\r\n\
    self.fail("Just an example")\r\n\
\r\n\
## Main entry point\r\n\
#Some normal *Markdown* paragraph text, the example \r\n\
#heading should line up with the if statement.\r\n\
if __name__ == "__main__":\r\n\
  # This comment, starting after column 0, is a normal comment shown\r\n\
  # inline with the code instead of one that is shown in the left panel.\r\n\
  unittest.main()\r\n\
""")
            subprocess.check_call(git + ["add", path])
        ## write file .gitbrowser-project.json
            path = os.path.join(temp_dir, ".gitbrowser-project.json")
            with open(path, "wb") as fh:
                fh.write('{"title": "Example Project"}')
            subprocess.check_call(git + ["add", path])
        ## write file subfolder/README 
            path = os.path.join(temp_dir, "subfolder", "README")
            os.makedirs(os.path.dirname(path))
            with open(path, "wb") as fh:
                fh.write("A file in a subfolder with a [parent link](..)")
            subprocess.check_call(git + ["add", path])
            subprocess.check_call(git + ["commit", "-m", "Update"])
        # Copy the git repository to the couchdb
            sync_script = os.path.join(self.source_path, "gitcouchdbsync.py")
            subprocess.check_call(cwd_script + ["python", sync_script,
                                                self.couchdb_url])
        # Run selenium testing against the public URL
        print "Uploaded. Running tests..."
        self._go_to_the_selenium_stage()