launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #02113
[Merge] lp:~benji/launchpad/bug-678375 into lp:launchpad
Benji York has proposed merging lp:~benji/launchpad/bug-678375 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#678375 preflight check for librarian access on appservers
https://bugs.launchpad.net/bugs/678375
Bug 678375 describes a smoke test script for the librarian that would
test the current librarian-related configuration and exit with 0 if
successful or 1 if there is an error.
This branch contains an implementation of that script.
The script itself (utilities/smoke-test-librarian.py) is just a shell
around the module at lib/canonical/librarian/tests/test_smoketest.py.
The tests are located at lib/canonical/librarian/tests/test_smoketest.py
and can be run with the command "bin/test test_smoketest".
The only lint reported is the erroneous:
./utilities/smoke-test-librarian.py
9: '_pythonpath' imported but unused
--
https://code.launchpad.net/~benji/launchpad/bug-678375/+merge/42884
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~benji/launchpad/bug-678375 into lp:launchpad.
=== added file 'lib/canonical/librarian/smoketest.py'
--- lib/canonical/librarian/smoketest.py 1970-01-01 00:00:00 +0000
+++ lib/canonical/librarian/smoketest.py 2010-12-06 22:59:10 +0000
@@ -0,0 +1,64 @@
+#! /usr/bin/python -S
+#
+# Copyright 2010 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Perform simple librarian operations to verify the current configuration.
+"""
+
+from cStringIO import StringIO
+import datetime
+import urllib
+
+from zope.component import getUtility
+import pytz
+import transaction
+
+from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
+
+
+FILE_SIZE = 1024
+FILE_DATA = 'x' * FILE_SIZE
+FILE_LIFETIME = datetime.timedelta(hours=1)
+
+
+def store_file(client):
+ file_id = client.addFile(
+ 'smoke-test-file', FILE_SIZE, StringIO(FILE_DATA), 'text/plain',
+ expires=datetime.datetime.now(pytz.UTC)+FILE_LIFETIME)
+ # To be able to retrieve the file, we must commit the current transaction.
+ transaction.commit()
+ alias = getUtility(ILibraryFileAliasSet)[file_id]
+ return alias.http_url
+
+
+def read_file(url):
+ try:
+ data = urllib.urlopen(url).read()
+ except (MemoryError, KeyboardInterrupt, SystemExit):
+ # Re-raise catastrophic errors.
+ raise
+ except:
+ # An error is represented by returning None, which won't match when
+ # comapred against FILE_DATA.
+ return None
+
+ return data
+
+
+def main(restricted_client, regular_client):
+ print 'adding a private file to the librarian...'
+ private_url = store_file(restricted_client)
+ print 'retrieving private file from', private_url
+ if read_file(private_url) != FILE_DATA:
+ print 'ERROR: data fetched does not match data written'
+ return 1
+
+ print 'adding a public file to the librarian...'
+ public_url = store_file(regular_client)
+ print 'retrieving public file from', public_url
+ if read_file(public_url) != FILE_DATA:
+ print 'ERROR: data fetched does not match data written'
+ return 1
+
+ return 0
=== added file 'lib/canonical/librarian/tests/test_smoketest.py'
--- lib/canonical/librarian/tests/test_smoketest.py 1970-01-01 00:00:00 +0000
+++ lib/canonical/librarian/tests/test_smoketest.py 2010-12-06 22:59:10 +0000
@@ -0,0 +1,108 @@
+# Copyright 2010 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Test the script that does a smoke-test of the librarian."""
+
+__metaclass__ = type
+
+from cStringIO import StringIO
+from contextlib import contextmanager
+
+from canonical.librarian import smoketest
+from canonical.librarian.smoketest import (
+ FILE_DATA,
+ main,
+ store_file,
+ )
+from canonical.librarian.testing.fake import FakeLibrarian
+from canonical.testing.layers import ZopelessDatabaseLayer
+from lp.testing import TestCaseWithFactory
+
+
+class GoodUrllib:
+ """A urllib replacement for testing that returns good results."""
+
+ def urlopen(self, url):
+ return StringIO(FILE_DATA)
+
+
+class BadUrllib:
+ """A urllib replacement for testing that returns bad results."""
+
+ def urlopen(self, url):
+ return StringIO('bad data')
+
+
+class ErrorUrllib:
+ """A urllib replacement for testing that raises an exception."""
+
+ def urlopen(self, url):
+ raise IOError('network error')
+
+
+class ExplosiveUrllib:
+ """A urllib replacement that raises an "explosive" exception."""
+
+ def __init__(self, exception):
+ self.exception = exception
+
+ def urlopen(self, url):
+ raise self.exception
+
+
+@contextmanager
+def fake_urllib(fake):
+ original_urllib = smoketest.urllib
+ smoketest.urllib = fake
+ yield
+ smoketest.urllib = original_urllib
+
+
+class SmokeTestTestCase(TestCaseWithFactory):
+ """Class test for translation importer creation."""
+ layer = ZopelessDatabaseLayer
+
+ def setUp(self):
+ super(SmokeTestTestCase, self).setUp()
+ self.fake_librarian = self.useFixture(FakeLibrarian())
+
+ def test_store_file(self):
+ # Make sure that the function meant to store a file in the librarian
+ # and return the file's HTTP URL works.
+ self.assertEquals(
+ store_file(self.fake_librarian),
+ 'http://localhost:58000/93/smoke-test-file')
+
+ def test_good_data(self):
+ # If storing and retrieving both the public and private files work,
+ # the main function will return 0 (which will be used as the processes
+ # exit code to signal success).
+ with fake_urllib(GoodUrllib()):
+ self.assertEquals(
+ main(self.fake_librarian, self.fake_librarian),
+ 0)
+
+ def test_bad_data(self):
+ # If incorrect data is retrieved, the main function will return 1
+ # (which will be used as the processes exit code to signal an error).
+ with fake_urllib(BadUrllib()):
+ self.assertEquals(
+ main(self.fake_librarian, self.fake_librarian),
+ 1)
+
+ def test_exception(self):
+ # If an exception is raised when retrieving the data, the main
+ # function will return 1 (which will be used as the processes exit
+ # code to signal an error).
+ with fake_urllib(ErrorUrllib()):
+ self.assertEquals(
+ main(self.fake_librarian, self.fake_librarian),
+ 1)
+
+ def test_explosive_errors(self):
+ # If an "explosive" exception (an exception that should not be caught)
+ # is raised when retrieving the data it is re-raised.
+ for exception in MemoryError, SystemExit, KeyboardInterrupt:
+ with fake_urllib(ExplosiveUrllib(exception)):
+ self.assertRaises(exception,
+ main, self.fake_librarian, self.fake_librarian)
=== added file 'utilities/smoke-test-librarian.py'
--- utilities/smoke-test-librarian.py 1970-01-01 00:00:00 +0000
+++ utilities/smoke-test-librarian.py 2010-12-06 22:59:10 +0000
@@ -0,0 +1,26 @@
+#! /usr/bin/python -S
+#
+# Copyright 2010 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Perform simple librarian operations to verify the current configuration.
+"""
+
+import _pythonpath # Not lint, actually needed.
+
+import sys
+
+from zope.component import getUtility
+from canonical.launchpad.scripts import execute_zcml_for_scripts
+from canonical.librarian.interfaces import (
+ IRestrictedLibrarianClient,
+ ILibrarianClient,
+ )
+from canonical.librarian.smoketest import main
+
+
+if __name__ == '__main__':
+ execute_zcml_for_scripts()
+ restricted_client = getUtility(IRestrictedLibrarianClient)
+ regular_client = getUtility(ILibrarianClient)
+ sys.exit(main(restricted_client, regular_client))