From 8c1cc8c03f0c6602beda052738ae0aec6a4b75e1 Mon Sep 17 00:00:00 2001
From: Sebastien Robin <seb@nexedi.com>
Date: Tue, 30 Oct 2012 16:24:51 +0100
Subject: [PATCH] erp5testnode: add test for getAndUpdateFullRevisionList

---
 erp5/tests/testERP5TestNode.py | 88 ++++++++++++++++++++++++++++------
 erp5/util/testnode/testnode.py | 53 ++++++++++----------
 2 files changed, 103 insertions(+), 38 deletions(-)

diff --git a/erp5/tests/testERP5TestNode.py b/erp5/tests/testERP5TestNode.py
index 882dc82d92..4b168d9500 100644
--- a/erp5/tests/testERP5TestNode.py
+++ b/erp5/tests/testERP5TestNode.py
@@ -1,7 +1,7 @@
 from unittest import TestCase
 
 import sys
-sys.path[0:0] = [
+sys.path.extend([
     '/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/eggs/slapos.cookbook-0.65-py2.7.egg',
     '/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/eggs/zc.recipe.egg-1.3.2-py2.7.egg',
     '/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/eggs/zc.buildout-1.6.0_dev_SlapOS_010-py2.7.egg',
@@ -19,12 +19,13 @@ sys.path[0:0] = [
     '/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/eggs/meld3-0.6.8-py2.7.egg',
     '/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/eggs/Jinja2-2.6-py2.7.egg',
     '/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/eggs/Werkzeug-0.8.3-py2.7.egg',
-    ]
+    ])
 
 from erp5.util.testnode import TestNode
-import tempfile
-import shutil
 import os
+import shutil
+import subprocess
+import tempfile
 
 class ERP5TestNode(TestCase):
 
@@ -32,16 +33,23 @@ class ERP5TestNode(TestCase):
     self._tempdir = tempfile.mkdtemp()
     self.working_directory = os.path.join(self._tempdir, 'testnode')
     self.slapos_directory = os.path.join(self._tempdir, 'slapos')
+    self.remote_repository0 = os.path.join(self._tempdir, 'rep0')
+    self.remote_repository1 = os.path.join(self._tempdir, 'rep1')
     os.mkdir(self.working_directory)
     os.mkdir(self.slapos_directory)
-    self.remote_repository1 = os.path.join(self._tempdir, 'rep1')
-    self.remote_repository2 = os.path.join(self._tempdir, 'rep2')
+    os.mkdir(self.remote_repository0)
+    os.mkdir(self.remote_repository1)
 
   def tearDown(self):
     shutil.rmtree(self._tempdir, True)
 
   def getTestNode(self):
-    return TestNode(None, None)
+    def log(*args):
+      for arg in args:
+        print "TESTNODE LOG : %r" % (arg,)
+    # XXX how to get property the git path ?
+    config = {"git_binary": "/srv/slapgrid/slappart80/srv/runner/software/ba1e09f3364989dc92da955b64e72f8d/parts/git/bin/git"}
+    return TestNode(log, config)
 
   def updateNodeTestSuiteData(self, node_test_suite):
     node_test_suite.edit(working_directory=self.working_directory,
@@ -49,14 +57,50 @@ class ERP5TestNode(TestCase):
         project_title="Foo",
         test_suite_title="Foo-Test",
         vcs_repository_list=[
-            {'url': self.remote_repository1,
+            {'url': self.remote_repository0,
              'profile_path': 'software.cfg',
              'branch': 'master'},
-            {'url': self.remote_repository2,
-             'buildout_section_id': 'foo',
+            {'url': self.remote_repository1,
+             'buildout_section_id': 'rep1',
              'branch': 'master'}])
 
-  def test_01_GetDelNodeTestSuite(self):
+  def getCaller(self, **kw):
+    class Caller(object):
+
+      def __init__(self, **kw):
+        self.__dict__.update(**kw)
+
+      def __call__(self, command):
+        return subprocess.check_output(command, **self.__dict__)
+    return Caller(**kw)
+
+  def generateTestRepositoryList(self):
+    last_commit_list = []
+    for i, repository_path in enumerate([self.remote_repository0,
+                                        self.remote_repository1]):
+      call = self.getCaller(cwd=repository_path)
+      call("git init".split())
+      call("touch first_file".split())
+      call("git add first_file".split())
+      call("git commit -v -m first_commit".split() + ['--author="a b <a@b.c>"'])
+      my_file = open(os.path.join(repository_path, 'first_file'), 'w')
+      my_file.write("initial_content%i" % i)
+      my_file.close()
+      call("git commit -av -m next_commit".split() + ['--author="a b <a@b.c>"'])
+      output = call("git log --oneline".split())
+      output_line_list = output.split("\n")
+      self.assertEquals(3, len(output_line_list))
+      # remove additional return line
+      output_line_list = output_line_list[0:2]
+      expected_commit_list = ["next_commit", "first_commit"]
+      last_commit_list.append(output_line_list[0].split())
+      commit_list = [x.split()[1] for x in output_line_list]
+      self.assertEquals(expected_commit_list, commit_list)
+    # looks like [('d3d09e6', 'next_commit'), ('c4c15e0', 'next_commit')]
+    # for respectively rep0 and rep1
+    return last_commit_list
+
+  def test_01_getDelNodeTestSuite(self):
     """
     We should be able to get/delete NodeTestSuite objects inside test_node
     """
@@ -80,6 +124,9 @@ class ERP5TestNode(TestCase):
                       node_test_suite.working_directory)
 
   def test_03_constructProfile(self):
+    """
+    Check if the software profile is correctly generated
+    """
     test_node = self.getTestNode()
     node_test_suite = test_node.getNodeTestSuite('foo')
     self.updateNodeTestSuiteData(node_test_suite)
@@ -89,11 +136,24 @@ class ERP5TestNode(TestCase):
     profile = open(node_test_suite.custom_profile_path, 'r')
     expected_profile = """
 [buildout]
-extends = %s/testnode/foo/rep1/software.cfg
+extends = %s/testnode/foo/rep0/software.cfg
 
-[foo]
-repository = %s/testnode/foo/foo
+[rep1]
+repository = %s/testnode/foo/rep1
 branch = master
 """ % (self._tempdir, self._tempdir)
     self.assertEquals(expected_profile, profile.read())
     profile.close()
+
+  def test_04_getAndUpdateFullRevisionList(self):
+    """
+    Check if we clone correctly repositories and git right revisions
+    """
+    commit_list = self.generateTestRepositoryList()
+    test_node = self.getTestNode()
+    node_test_suite = test_node.getNodeTestSuite('foo')
+    self.updateNodeTestSuiteData(node_test_suite)
+    result = test_node.getAndUpdateFullRevisionList(node_test_suite)
+    self.assertEquals(2, len(result))
+    self.assertTrue(result[0].startswith('rep0=2-%s' % commit_list[0][0]))
+    self.assertTrue(result[1].startswith('rep1=2-%s' % commit_list[1][0]))
diff --git a/erp5/util/testnode/testnode.py b/erp5/util/testnode/testnode.py
index dcc15a6487..6cff03cbcc 100644
--- a/erp5/util/testnode/testnode.py
+++ b/erp5/util/testnode/testnode.py
@@ -58,6 +58,10 @@ class SlapOSInstance(object):
 
   def edit(self, **kw):
     self.__dict__.update(**kw)
+    self._checkData()
+
+  def _checkData(self):
+    pass
 
 class NodeTestSuite(SlapOSInstance):
 
@@ -66,14 +70,25 @@ class NodeTestSuite(SlapOSInstance):
     self.reference = reference
 
   def edit(self, **kw):
-    if kw.has_key("working_directory"):
-      kw["working_directory"] = os.path.join(kw["working_directory"],
-                                              self.reference)
-      SlapOSControler.createFolder(kw["working_directory"])
-      kw["custom_profile_path"] = os.path.join(kw['working_directory'],
-                                 'software.cfg')
     super(NodeTestSuite, self).edit(**kw)
 
+  def _checkData(self):
+    if getattr(self, "working_directory", None) is not None:
+      if not(self.working_directory.endswith(os.path.sep + self.reference)):
+        self.working_directory = os.path.join(self.working_directory,
+                                             self.reference)
+      SlapOSControler.createFolder(self.working_directory)
+      self.custom_profile_path = os.path.join(self.working_directory,
+                                 'software.cfg')
+    if getattr(self, "vcs_repository_list", None) is not None:
+      for vcs_repository in self.vcs_repository_list:
+        buildout_section_id = vcs_repository.get('buildout_section_id', None)
+        repository_id = buildout_section_id or \
+                        vcs_repository.get('url').split('/')[-1].split('.')[0]
+        repository_path = os.path.join(self.working_directory,repository_id)
+        vcs_repository['repository_id'] = repository_id
+        vcs_repository['repository_path'] = repository_path
+
 class TestNode(object):
 
   def __init__(self, log, config):
@@ -88,12 +103,12 @@ class TestNode(object):
 
   def checkOldTestSuite(self,test_suite_data):
     config = self.config
-    installed_reference_set = set(os.listdir(config['slapos_directory']))
+    installed_reference_set = set(os.listdir(config['working_directory']))
     wished_reference_set = set([x['test_suite_reference'] for x in test_suite_data])
     to_remove_reference_set = installed_reference_set.difference(
                                  wished_reference_set)
     for y in to_remove_reference_set:
-      fpath = os.path.join(config['slapos_directory'],y)
+      fpath = os.path.join(config['working_directory'],y)
       self.delNodeTestSuite(y)
       if os.path.isdir(fpath):
        shutil.rmtree(fpath)
@@ -115,23 +130,11 @@ class TestNode(object):
     config = self.config
     profile_content = ''
     assert len(node_test_suite.vcs_repository_list), "we must have at least one repository"
-    try:
-      # BBB: Accept global profile_path, which is the same as setting it for the
-      # first configured repository.
-      profile_path = config.pop(PROFILE_PATH_KEY)
-    except KeyError:
-      pass
-    else:
-      node_test_suite.vcs_repository_list[0][PROFILE_PATH_KEY] = profile_path
     profile_path_count = 0
     for vcs_repository in node_test_suite.vcs_repository_list:
       url = vcs_repository['url']
       buildout_section_id = vcs_repository.get('buildout_section_id', None)
-      repository_id = buildout_section_id or \
-                                  url.split('/')[-1].split('.')[0]
-      repository_path = os.path.join(node_test_suite.working_directory,repository_id)
-      vcs_repository['repository_id'] = repository_id
-      vcs_repository['repository_path'] = repository_path
+      repository_path = vcs_repository['repository_path']
       try:
         profile_path = vcs_repository[PROFILE_PATH_KEY]
       except KeyError:
@@ -158,7 +161,6 @@ branch = %(branch)s
     custom_profile = open(node_test_suite.custom_profile_path, 'w')
     custom_profile.write(profile_content)
     custom_profile.close()
-    config['repository_path'] = repository_path
     sys.path.append(repository_path)
 
   def getAndUpdateFullRevisionList(self, node_test_suite):
@@ -251,7 +253,7 @@ branch = %(branch)s
     We will build slapos software needed by the testnode itself,
     like the building of selenium-runner by default
     """
-    return self._prepareSlapOS(self.config['slapos_directory'],
+    self._prepareSlapOS(self.config['slapos_directory'],
               test_node_slapos, create_partition=0,
               software_path_list=self.config.get("software_list"))
 
@@ -304,7 +306,7 @@ branch = %(branch)s
 
   def cleanUp(self,test_result):
     log = self.log
-    log('Testnode.run, finally close')
+    log('Testnode.cleanUp')
     self.process_manager.killPreviousRun()
     if test_result is not None:
       try:
@@ -324,6 +326,7 @@ branch = %(branch)s
     try:
       while True:
         try:
+          self.cleanUp(None)
           remote_test_result_needs_cleanup = False
           begin = time.time()
           self.prepareSlapOSForTestNode(test_node_slapos)
@@ -367,6 +370,7 @@ branch = %(branch)s
               time.sleep(20)
               self.runTestSuite(node_test_suite,portal_url, slapos_controler)
               test_result.removeWatch(log_file_name)
+            self.cleanUp(test_result)
         except (SubprocessError, CalledProcessError) as e:
           log("SubprocessError", exc_info=sys.exc_info())
           if test_result is not None:
@@ -401,4 +405,5 @@ branch = %(branch)s
       # Nice way to kill *everything* generated by run process -- process
       # groups working only in POSIX compilant systems
       # Exceptions are swallowed during cleanup phas
+      log("GENERAL EXCEPTION, QUITING")
       self.cleanUp(test_result)
-- 
2.30.9