[csw-devel] SF.net SVN: gar:[13107] csw/mgar/gar/v2

wahwah at users.sourceforge.net wahwah at users.sourceforge.net
Sat Jan 29 16:48:42 CET 2011


Revision: 13107
          http://gar.svn.sourceforge.net/gar/?rev=13107&view=rev
Author:   wahwah
Date:     2011-01-29 15:48:41 +0000 (Sat, 29 Jan 2011)

Log Message:
-----------
catalog_notifier: Initial commit

Initial inquiry in the mailing list:
http://lists.opencsw.org/pipermail/maintainers/2011-January/013865.html

This is the first iteration of implementation of the notifier.

It needs to be used with caution, because of the potential of spamming
people.

Notes:

 - It stores previous catalog state in a pickle file
 - It does not store history, only the previous version
 - It does not support locking
 - Allows whitelisting for testing
 - Default behavior is not to send e-mail, but only print to screen

Modified Paths:
--------------
    csw/mgar/gar/v2/lib/python/catalog.py
    csw/mgar/gar/v2/lib/python/catalog_test.py
    csw/mgar/gar/v2/tests/run_tests.py

Added Paths:
-----------
    csw/mgar/gar/v2/lib/python/catalog_notifier.py
    csw/mgar/gar/v2/lib/python/catalog_notifier_test.py

Modified: csw/mgar/gar/v2/lib/python/catalog.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog.py	2011-01-29 15:48:01 UTC (rev 13106)
+++ csw/mgar/gar/v2/lib/python/catalog.py	2011-01-29 15:48:41 UTC (rev 13107)
@@ -174,8 +174,14 @@
 
   def GetCatalogDiff(self, cat_a, cat_b):
     """Returns a difference between two catalogs."""
-    bc_a = cat_a.GetDataByCatalogname()
-    bc_b = cat_b.GetDataByCatalogname()
+    if type(cat_a) == dict:
+      bc_a = cat_a
+    else:
+      bc_a = cat_a.GetDataByCatalogname()
+    if type(cat_b) == dict:
+      bc_b = cat_b
+    else:
+      bc_b = cat_b.GetDataByCatalogname()
     cn_a = set(bc_a)
     cn_b = set(bc_b)
     new_catalognames = cn_b.difference(cn_a)

Added: csw/mgar/gar/v2/lib/python/catalog_notifier.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog_notifier.py	                        (rev 0)
+++ csw/mgar/gar/v2/lib/python/catalog_notifier.py	2011-01-29 15:48:41 UTC (rev 13107)
@@ -0,0 +1,274 @@
+#!/usr/bin/env python2.6
+
+"""Polls a designated catalog tree, and sends notifications about
+package updates."""
+
+import optparse
+import catalog
+import common_constants
+from Cheetah import Template
+import urllib2
+import logging
+import configuration
+import pprint
+import cPickle
+import json
+import os.path
+import smtplib
+from email.mime.text import MIMEText
+
+REPORT_TMPL = u"""Catalog update report for $email
+Catalog URL: $url
+#if "new_pkgs" in $pkg_data
+
+New packages:
+#for basename in $pkg_data["new_pkgs"]
+* $basename
+  In catalogs:
+#for catalog in $sorted($pkg_data["new_pkgs"][basename]["catalogs"])
+  - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "removed_pkgs" in $pkg_data
+
+Removed packages:
+#for basename in $pkg_data["removed_pkgs"]
+* $basename
+  From catalogs:
+#for catalog in $sorted($pkg_data["removed_pkgs"][basename]["catalogs"])
+  - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "upgraded_pkg" in $pkg_data
+
+Version change (probably upgrade):
+#for basename in $pkg_data["upgraded_pkg"]
+* $basename
+  In catalogs:
+#for catalog in $sorted($pkg_data["upgraded_pkg"][basename]["catalogs"])
+  - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "lost_pkg" in $pkg_data
+
+You no longer maintain packages:
+#for basename in $pkg_data["lost_pkg"]
+* $basename
+  In catalogs:
+#for catalog in $sorted($pkg_data["lost_pkg"][basename]["catalogs"])
+  - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+#if "got_pkg" in $pkg_data
+
+You took over packages:
+#for basename in $pkg_data["got_pkg"]
+* $basename
+  In catalogs:
+#for catalog in $sorted($pkg_data["got_pkg"][basename]["catalogs"])
+  - $catalog[0] $catalog[1] $catalog[2]
+#end for
+#end for
+#end if
+"""
+
+class RestClient(object):
+
+  def GetPkgByMd5(self, md5_sum):
+    url = "http://buildfarm.opencsw.org/pkgdb/rest/srv4/%s/" % md5_sum
+    logging.debug("GetPkgByMd5(): calling %s", url)
+    data = urllib2.urlopen(url).read()
+    return json.loads(data)
+
+  def GetMaintainerByMd5(self, md5_sum):
+    pkg = self.GetPkgByMd5(md5_sum)
+    return {
+        "maintainer_email": pkg["maintainer_email"],
+    }
+
+
+class NotificationFormatter(object):
+
+  def _GetPkgsByMaintainer(self, catalogs, rest_client):
+    c = catalog.CatalogComparator()
+    pkgs_by_maintainer = {}
+    for catrel, arch, osrel, cat_a, cat_b in catalogs:
+      catalog_key = (catrel, arch, osrel)
+      new_pkgs, removed_pkgs, updated_pkgs = c.GetCatalogDiff(cat_a, cat_b)
+      labels_and_lists = (
+          ("new_pkgs", new_pkgs),
+          ("removed_pkgs", removed_pkgs),
+      )
+      for label, pkg_list in labels_and_lists:
+        for pkg in pkg_list:
+          maintainer = rest_client.GetMaintainerByMd5(pkg["md5sum"])
+          maintainer_email = maintainer["maintainer_email"]
+          pkgs_by_maintainer.setdefault(maintainer_email, {})
+          pkgs_by_maintainer[maintainer_email].setdefault(label, {})
+          labeled = pkgs_by_maintainer[maintainer_email][label]
+          basename = pkg["file_basename"]
+          labeled.setdefault(basename, {
+            "pkg": pkg,
+            "catalogs": [],
+          })
+          labeled[basename]["catalogs"].append(catalog_key)
+      for d in updated_pkgs:
+        from_pkg = d["from"]
+        to_pkg = d["to"]
+        maintainer_from = rest_client.GetMaintainerByMd5(from_pkg["md5sum"])
+        maintainer_to = rest_client.GetMaintainerByMd5(to_pkg["md5sum"])
+        from_email = maintainer_from["maintainer_email"]
+        to_email = maintainer_to["maintainer_email"]
+        if from_email == to_email:
+          # A normal upgrade, no takeover
+          label = "upgraded_pkg"
+          self._StorePkgUpdate(catalog_key,
+              label, pkgs_by_maintainer, from_email, from_pkg, to_pkg)
+        else:
+          # Package takeover
+          self._StorePkgUpdate(catalog_key,
+              "lost_pkg", pkgs_by_maintainer, from_email, from_pkg, to_pkg)
+          self._StorePkgUpdate(catalog_key,
+              "got_pkg", pkgs_by_maintainer, to_email, from_pkg, to_pkg)
+    return pkgs_by_maintainer
+
+  def _StorePkgUpdate(self,
+      catalog_key,
+      label, pkgs_by_maintainer, email, from_pkg, to_pkg):
+    pkgs_by_maintainer.setdefault(email, {})
+    pkgs_by_maintainer[email].setdefault(label, {})
+    labeled = pkgs_by_maintainer[email][label]
+    basename = to_pkg["file_basename"]
+    labeled.setdefault(basename, {
+      "to_pkg": to_pkg,
+      "from_pkg": {},
+      "catalogs": [],
+    })
+    labeled[basename]["from_pkg"][from_pkg["file_basename"]] = from_pkg
+    labeled[basename]["catalogs"].append(catalog_key)
+
+  def _RenderForMaintainer(self, pkg_data, email, url):
+    namespace = {
+        "pkg_data": pkg_data,
+        "email": email,
+        "url": url}
+    t = Template.Template(REPORT_TMPL, searchList=[namespace])
+    return unicode(t)
+
+  def FormatNotifications(self, url, catalogs, rest_client):
+    """Formats a notification from a series of catalogs.
+
+    Args:
+      url: Base URL for catalogs
+      catalogs: A list of triplets (catrel, arch, osrel, cat_a, cat_b)
+      rest_client: An interface to the outside world
+    """
+    pkgs_by_maintainer = self._GetPkgsByMaintainer(catalogs, rest_client)
+    rendered_notifications = {}
+    for email in pkgs_by_maintainer:
+      rendered_notifications[email] = self._RenderForMaintainer(
+          pkgs_by_maintainer[email], email, url)
+    return rendered_notifications
+
+
+class CatalogIndexDownloader(object):
+
+  def GetCatalogsByTriad(self, cat_tree_url):
+    catalogs_by_triad = {}
+    for catrel in common_constants.DEFAULT_CATALOG_RELEASES:
+      for arch in common_constants.PHYSICAL_ARCHITECTURES:
+        for osrel in common_constants.OS_RELS:
+          short_osrel = osrel.replace("SunOS", "")
+          catalog_file_url = (
+              "%s%s/%s/%s/catalog"
+              % (cat_tree_url, catrel, arch, short_osrel))
+          logging.info("Opening %s", repr(catalog_file_url))
+          try:
+            f = urllib2.urlopen(catalog_file_url)
+            key = (catrel, arch, osrel)
+            catalog_instance = catalog.OpencswCatalog(f)
+            catalogs_by_triad[key] = catalog_instance.GetDataByCatalogname()
+          except urllib2.URLError, e:
+            logging.warning(e)
+    return catalogs_by_triad
+
+
+def main():
+  DEFAULT_URL = "http://mirror.opencsw.org/opencsw/"
+  DEFAULT_URL = "http://ivy.home.blizinski.pl/~maciej/opencsw/"
+  parser = optparse.OptionParser()
+  parser.add_option("-u", "--url",
+      dest="url", help="Base URL of OpenCSW catalog",
+      default=DEFAULT_URL)
+  parser.add_option("-d", "--debug",
+      dest="debug", action="store_true",
+      default=False)
+  parser.add_option("-s", "--send-notifications",
+      dest="send_notifications", action="store_true",
+      default=False)
+  parser.add_option("-p", "--pickle-file",
+      dest="pickle_file", help="Pickle file",
+      default="/tmp/opencsw-notifier-data/example.pickle")
+  parser.add_option("-w", "--whitelist",
+      dest="whitelist",
+      help="E-mail address whitelist, comma separated",
+      default=None)
+  options, args = parser.parse_args()
+  logging.basicConfig(level=logging.DEBUG)
+  # Getting catalogs
+  cat_tree_url = options.url
+  downloader = CatalogIndexDownloader()
+  catalogs_by_triad = downloader.GetCatalogsByTriad(cat_tree_url)
+  pickle_path = options.pickle_file
+  previous_catalogs_by_triad = None
+  try:
+    with open(pickle_path, "rb") as fd:
+      previous_catalogs_by_triad = cPickle.load(fd)
+  except (IOError, EOFError), e:
+    logging.warning(e)
+    previous_catalogs_by_triad = {}
+  # Merge the two data structures here
+  catalogs = []
+  for key in catalogs_by_triad:
+    if key in previous_catalogs_by_triad:
+      catalogs.append(
+        # ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+        key + (previous_catalogs_by_triad[key], catalogs_by_triad[key])
+      )
+    else:
+      logging.debug("%s not found in previous_catalogs_by_triad", key)
+  formatter = NotificationFormatter()
+  rest_client = RestClient()
+  notifications = formatter.FormatNotifications(
+      cat_tree_url, catalogs, rest_client)
+  whitelist = frozenset()
+  if options.whitelist:
+    whitelist = frozenset(options.whitelist.split(","))
+    logging.debug("Email whitelist: %s", whitelist)
+  for email in notifications:
+    if options.send_notifications:
+      logging.debug("email: %s", repr(email))
+      if email not in whitelist: continue
+      logging.debug("Sending.")
+      msg = MIMEText(notifications[email])
+      msg["Subject"] = "OpenCSW catalog update report"
+      from_address = "Catalog update notifier <noreply at opencsw.org>"
+      msg['From'] = from_address
+      msg['To'] = email
+      s = smtplib.SMTP('localhost')
+      s.sendmail(from_address, [email], msg.as_string())
+      s.quit()
+      logging.debug("E-mail sent.")
+    else:
+      print notifications[email]
+      print "* * *"
+  with open(pickle_path, "wb") as fd:
+    cPickle.dump(catalogs_by_triad, fd)
+
+
+if __name__ == '__main__':
+  main()


Property changes on: csw/mgar/gar/v2/lib/python/catalog_notifier.py
___________________________________________________________________
Added: svn:executable
   + *

Added: csw/mgar/gar/v2/lib/python/catalog_notifier_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog_notifier_test.py	                        (rev 0)
+++ csw/mgar/gar/v2/lib/python/catalog_notifier_test.py	2011-01-29 15:48:41 UTC (rev 13107)
@@ -0,0 +1,186 @@
+#!/usr/bin/env python2.6
+
+import unittest
+import mox
+import catalog_notifier
+import catalog
+import catalog_test
+import copy
+import pprint
+
+
+class NotificationFormatterTest(mox.MoxTestBase):
+  
+  def disabled_testOne(self):
+    """This tested too much."""
+    f = catalog_notifier.NotificationFormatter()
+    rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+    url = "http://www.example.com/opencsw/"
+    cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+    cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+    catalogs = [
+        ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+    ]
+    maintainers = {
+        "cfe40c06e994f6e8d3b191396d0365cb": {"maintainer_email": "joe at example.com"},
+    }
+    cat_a.GetDataByCatalogname().AndReturn({})
+    cat_b.GetDataByCatalogname().AndReturn({"syslog_ng": catalog_test.PKG_STRUCT_1})
+    self.mox.ReplayAll()
+    self.assertEqual(
+        "report here",
+        f.FormatNotification(url, catalogs, rest_client_mock))
+
+  def test_GetPkgsByMaintainerNew(self):
+    f = catalog_notifier.NotificationFormatter()
+    rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+    cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+    cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+    catalogs = [
+        ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+    ]
+    rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+        {"maintainer_email": "joe at example.com"}
+    )
+    cat_a.GetDataByCatalogname().AndReturn({})
+    cat_b.GetDataByCatalogname().AndReturn({
+      "syslog_ng": catalog_test.PKG_STRUCT_1,
+    })
+    self.mox.ReplayAll()
+    expected = {'joe at example.com': {
+      'new_pkgs': {
+        catalog_test.PKG_STRUCT_1["file_basename"]: {
+          "pkg": catalog_test.PKG_STRUCT_1,
+          "catalogs": [
+            ("fossil", "amd65", "SolarOS5.12"),
+          ],
+        },
+      }}
+    }
+    self.assertEqual(
+        expected,
+        f._GetPkgsByMaintainer(catalogs, rest_client_mock))
+    expected_text = u"""aa"""
+    # Uncomment to see rendered template
+    # print f._RenderForMaintainer(expected["joe at example.com"])
+
+  def test_GetPkgsByMaintainerRemoved(self):
+    f = catalog_notifier.NotificationFormatter()
+    rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+    cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+    cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+    catalogs = [
+        ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+    ]
+    rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+        {"maintainer_email": "joe at example.com"}
+    )
+    cat_a.GetDataByCatalogname().AndReturn({
+      "syslog_ng": catalog_test.PKG_STRUCT_1,
+    })
+    cat_b.GetDataByCatalogname().AndReturn({})
+    self.mox.ReplayAll()
+    expected = {'joe at example.com': {
+      'removed_pkgs': {
+        catalog_test.PKG_STRUCT_1["file_basename"]: {
+          "pkg": catalog_test.PKG_STRUCT_1,
+          "catalogs": [
+            ("fossil", "amd65", "SolarOS5.12"),
+          ],
+        },
+      }}
+    }
+    self.assertEqual(
+        expected,
+        f._GetPkgsByMaintainer(catalogs, rest_client_mock))
+    expected_text = u"""aa"""
+    # Uncomment to see rendered template
+    # print f._RenderForMaintainer(expected["joe at example.com"])
+
+  def test_GetPkgsByMaintainerTakeover(self):
+    f = catalog_notifier.NotificationFormatter()
+    rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+    cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+    cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+    catalogs = [
+        ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+    ]
+    previous_pkg = copy.deepcopy(catalog_test.PKG_STRUCT_1)
+    previous_pkg["version"] = "previous_version"
+    previous_pkg["md5sum"] = "previous_md5"
+    cat_a.GetDataByCatalogname().AndReturn({
+      "syslog_ng": previous_pkg,
+    })
+    cat_b.GetDataByCatalogname().AndReturn({
+      "syslog_ng": catalog_test.PKG_STRUCT_1,
+    })
+    rest_client_mock.GetMaintainerByMd5('previous_md5').AndReturn(
+        {"maintainer_email": "jack at example.com"}
+    )
+    rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+        {"maintainer_email": "joe at example.com"}
+    )
+    self.mox.ReplayAll()
+    result = f._GetPkgsByMaintainer(catalogs, rest_client_mock)
+    self.assertTrue("jack at example.com" in result)
+    self.assertEqual({"lost_pkg": {
+      catalog_test.PKG_STRUCT_1["file_basename"]: {
+        "from_pkg": {previous_pkg["file_basename"]: previous_pkg},
+        "to_pkg": catalog_test.PKG_STRUCT_1,
+        "catalogs": [("fossil", "amd65", "SolarOS5.12")],
+        }}},
+      result["jack at example.com"])
+    self.assertEqual({"got_pkg": {
+      catalog_test.PKG_STRUCT_1["file_basename"]: {
+        "from_pkg": {previous_pkg["file_basename"]: previous_pkg},
+        "to_pkg": catalog_test.PKG_STRUCT_1,
+        "catalogs": [("fossil", "amd65", "SolarOS5.12")],
+        }}},
+      result["joe at example.com"])
+    # Uncomment to see rendered templates
+    # print f._RenderForMaintainer(
+    #     result["jack at example.com"], "jack at example.com",
+    #     "http://mirror.example.com")
+    # print f._RenderForMaintainer(
+    #     result["joe at example.com"], "joe at example.com",
+    #     "http://mirror.example.com")
+
+  def test_GetPkgsByMaintainerUpgrade(self):
+    f = catalog_notifier.NotificationFormatter()
+    rest_client_mock = self.mox.CreateMock(catalog_notifier.RestClient)
+    cat_a = self.mox.CreateMock(catalog.OpencswCatalog)
+    cat_b = self.mox.CreateMock(catalog.OpencswCatalog)
+    catalogs = [
+        ("fossil", "amd65", "SolarOS5.12", cat_a, cat_b),
+    ]
+    previous_pkg = copy.deepcopy(catalog_test.PKG_STRUCT_1)
+    previous_pkg["version"] = "previous_version"
+    previous_pkg["md5sum"] = "previous_md5"
+    cat_a.GetDataByCatalogname().AndReturn({
+      "syslog_ng": previous_pkg,
+    })
+    cat_b.GetDataByCatalogname().AndReturn({
+      "syslog_ng": catalog_test.PKG_STRUCT_1,
+    })
+    rest_client_mock.GetMaintainerByMd5('previous_md5').AndReturn(
+        {"maintainer_email": "jack at example.com"}
+    )
+    rest_client_mock.GetMaintainerByMd5('cfe40c06e994f6e8d3b191396d0365cb').AndReturn(
+        {"maintainer_email": "jack at example.com"}
+    )
+    self.mox.ReplayAll()
+    result = f._GetPkgsByMaintainer(catalogs, rest_client_mock)
+    # pprint.pprint(result)
+    self.assertTrue("jack at example.com" in result)
+    # In this scenario, we group packages by the target package (after upgrade)
+    self.assertEqual({"upgraded_pkg": {
+      catalog_test.PKG_STRUCT_1["file_basename"]: {
+        "from_pkg": {previous_pkg["file_basename"]: previous_pkg},
+        "to_pkg": catalog_test.PKG_STRUCT_1,
+        "catalogs": [("fossil", "amd65", "SolarOS5.12")],
+        }}},
+      result["jack at example.com"])
+
+
+if __name__ == '__main__':
+  unittest.main()


Property changes on: csw/mgar/gar/v2/lib/python/catalog_notifier_test.py
___________________________________________________________________
Added: svn:executable
   + *

Modified: csw/mgar/gar/v2/lib/python/catalog_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/catalog_test.py	2011-01-29 15:48:01 UTC (rev 13106)
+++ csw/mgar/gar/v2/lib/python/catalog_test.py	2011-01-29 15:48:41 UTC (rev 13107)
@@ -25,8 +25,21 @@
         '145351cf6186fdcadcd169b66387f72f 214091 '
         'CSWcommon|CSWlibevent none none\n')
 
+PKG_STRUCT_1 = {
+    'category': 'none',
+    'i_deps': (),
+    'pkgname': 'CSWsyslogng',
+    'md5sum': 'cfe40c06e994f6e8d3b191396d0365cb',
+    'version': '3.0.4,REV=2009.08.30',
+    'deps': ('CSWgcc4corert', 'CSWeventlog', 'CSWosslrt', 'CSWzlib',
+      'CSWpcrert', 'CSWggettextrt', 'CSWglib2', 'CSWtcpwrap',
+      'CSWcswclassutils', 'CSWcommon'),
+    'file_basename': 'syslog_ng-3.0.4,REV=2009.08.30-SunOS5.8-i386-CSW.pkg.gz',
+    'size': '137550',
+    'catalogname': 'syslog_ng'}
 
 
+
 class OpencswCatalogUnitTest(unittest.TestCase):
 
   def test_ParseCatalogLine_1(self):
@@ -44,20 +57,9 @@
     self.assertEquals(expected, parsed)
 
   def testGetDataByCatalogname(self):
-    expected = {'syslog_ng': {
-      'category': 'none',
-      'i_deps': (),
-      'pkgname': 'CSWsyslogng',
-      'md5sum': 'cfe40c06e994f6e8d3b191396d0365cb',
-      'version': '3.0.4,REV=2009.08.30',
-      'deps': ('CSWgcc4corert', 'CSWeventlog', 'CSWosslrt', 'CSWzlib',
-        'CSWpcrert', 'CSWggettextrt', 'CSWglib2', 'CSWtcpwrap',
-        'CSWcswclassutils', 'CSWcommon'),
-      'file_basename': 'syslog_ng-3.0.4,REV=2009.08.30-SunOS5.8-i386-CSW.pkg.gz',
-      'size': '137550',
-      'catalogname': 'syslog_ng'}}
     fd = StringIO(CATALOG_LINE_1)
     oc = catalog.OpencswCatalog(fd)
+    expected = {"syslog_ng": PKG_STRUCT_1}
     self.assertEqual(expected, oc.GetDataByCatalogname())
 
 

Modified: csw/mgar/gar/v2/tests/run_tests.py
===================================================================
--- csw/mgar/gar/v2/tests/run_tests.py	2011-01-29 15:48:01 UTC (rev 13106)
+++ csw/mgar/gar/v2/tests/run_tests.py	2011-01-29 15:48:41 UTC (rev 13107)
@@ -12,6 +12,7 @@
 # To add more test files, create <name>.py file and add a corresponding line
 # here:
 from catalog_test            import *
+from catalog_notifier_test   import *
 from checkpkg_lib_test       import *
 from checkpkg_test           import *
 from dependency_checks_test  import *


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.


More information about the devel mailing list