Esempio n. 1
0
 def setUp(self):
     super(TestBranchFileSystemClient, self).setUp()
     frontend = InMemoryFrontend()
     self.factory = frontend.getLaunchpadObjectFactory()
     self.user = self.factory.makePerson()
     self._xmlrpc_client = XMLRPCWrapper(frontend.getCodehostingEndpoint())
     self.fake_time = FakeTime(12345)
 def setUp(self):
     super(TestBranchFileSystemClient, self).setUp()
     frontend = InMemoryFrontend()
     self.factory = frontend.getLaunchpadObjectFactory()
     self.user = self.factory.makePerson()
     self._xmlrpc_client = XMLRPCWrapper(frontend.getCodehostingEndpoint())
     self.fake_time = FakeTime(12345)
Esempio n. 3
0
 def setUp(self):
     super(TestBranchRewriter, self).setUp()
     self.fake_time = FakeTime(0)
Esempio n. 4
0
class TestBranchRewriter(TestCaseWithFactory):

    layer = DatabaseFunctionalLayer

    def setUp(self):
        super(TestBranchRewriter, self).setUp()
        self.fake_time = FakeTime(0)

    def makeRewriter(self):
        return BranchRewriter(BufferLogger(), self.fake_time.now)

    def getLoggerOutput(self, rewriter):
        return rewriter.logger.getLogBuffer()

    def test_rewriteLine_found_dot_bzr(self):
        # Requests for /$branch_name/.bzr/... are redirected to where the
        # branches are served from by ID.
        rewriter = self.makeRewriter()
        branches = [
            self.factory.makeProductBranch(),
            self.factory.makePersonalBranch(),
            self.factory.makePackageBranch()
        ]
        transaction.commit()
        output = [
            rewriter.rewriteLine("/%s/.bzr/README" % branch.unique_name)
            for branch in branches
        ]
        expected = [
            'file:///var/tmp/bazaar.launchpad.dev/mirrors/%s/.bzr/README' %
            branch_id_to_path(branch.id) for branch in branches
        ]
        self.assertEqual(expected, output)

    def test_rewriteLine_found_not_dot_bzr(self):
        # Requests for /$branch_name/... that are not to .bzr directories are
        # redirected to codebrowse.
        rewriter = self.makeRewriter()
        branches = [
            self.factory.makeProductBranch(),
            self.factory.makePersonalBranch(),
            self.factory.makePackageBranch()
        ]
        transaction.commit()
        output = [
            rewriter.rewriteLine("/%s/changes" % branch.unique_name)
            for branch in branches
        ]
        expected = [
            'http://localhost:8080/%s/changes' % branch.unique_name
            for branch in branches
        ]
        self.assertEqual(expected, output)

    def test_rewriteLine_private(self):
        # All requests for /$branch_name/... for private branches are
        # rewritten to codebrowse, which will then redirect them to https and
        # handle them there.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch(
            information_type=InformationType.USERDATA)
        unique_name = removeSecurityProxy(branch).unique_name
        transaction.commit()
        output = [
            rewriter.rewriteLine("/%s/changes" % unique_name),
            rewriter.rewriteLine("/%s/.bzr" % unique_name)
        ]
        self.assertEqual([
            'http://localhost:8080/%s/changes' % unique_name,
            'http://localhost:8080/%s/.bzr' % unique_name
        ], output)

    def test_rewriteLine_id_alias_found_dot_bzr(self):
        # Requests for /+branch-id/$id/.bzr/... are redirected to where the
        # branches are served from by ID if they are public.
        rewriter = self.makeRewriter()
        branches = [
            self.factory.makeProductBranch(),
            self.factory.makePersonalBranch(),
            self.factory.makePackageBranch()
        ]
        transaction.commit()
        output = [
            rewriter.rewriteLine("%s/.bzr/README" % branch_id_alias(branch))
            for branch in branches
        ]
        expected = [
            'file:///var/tmp/bazaar.launchpad.dev/mirrors/%s/.bzr/README' %
            branch_id_to_path(branch.id) for branch in branches
        ]
        self.assertEqual(expected, output)

    def test_rewriteLine_id_alias_private(self):
        # All requests for /+branch-id/$id/... for private branches return
        # 'NULL'.  This is translated by apache to a 404.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch(
            information_type=InformationType.USERDATA)
        path = branch_id_alias(removeSecurityProxy(branch))
        transaction.commit()
        output = [
            rewriter.rewriteLine("%s/changes" % path),
            rewriter.rewriteLine("%s/.bzr" % path)
        ]
        self.assertEqual(['NULL', 'NULL'], output)

    def test_rewriteLine_id_alias_logs_cache_hit(self):
        # The second request for a branch using the alias hits the cache.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        path = "%s/.bzr/README" % branch_id_alias(branch)
        rewriter.rewriteLine(path)
        rewriter.rewriteLine(path)
        logging_output_lines = self.getLoggerOutput(rewriter).strip().split(
            '\n')
        self.assertEqual(2, len(logging_output_lines))
        self.assertIsNot(
            None,
            re.match("INFO .* -> .* (.*s, cache: HIT)",
                     logging_output_lines[-1]),
            "No hit found in %r" % logging_output_lines[-1])

    def test_rewriteLine_static(self):
        # Requests to /static are rewritten to codebrowse urls.
        rewriter = self.makeRewriter()
        output = rewriter.rewriteLine("/static/foo")
        self.assertEqual('http://localhost:8080/static/foo', output)

    def test_rewriteLine_not_found(self):
        # If the request does not map to a branch, we redirect it to
        # codebrowse as it can generate a 404.
        rewriter = self.makeRewriter()
        not_found_path = "/~nouser/noproduct"
        output = rewriter.rewriteLine(not_found_path)
        self.assertEqual('http://localhost:8080%s' % not_found_path, output)

    def test_rewriteLine_logs_cache_miss(self):
        # The first request for a branch misses the cache and logs this fact.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        rewriter.rewriteLine('/' + branch.unique_name + '/.bzr/README')
        logging_output = self.getLoggerOutput(rewriter)
        self.assertIsNot(
            None, re.match("INFO .* -> .* (.*s, cache: MISS)", logging_output),
            "No miss found in %r" % logging_output)

    def test_rewriteLine_logs_cache_hit(self):
        # The second request for a branch misses the cache and logs this fact.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        rewriter.rewriteLine('/' + branch.unique_name + '/.bzr/README')
        rewriter.rewriteLine('/' + branch.unique_name + '/.bzr/README')
        logging_output_lines = self.getLoggerOutput(rewriter).strip().split(
            '\n')
        self.assertEqual(2, len(logging_output_lines))
        self.assertIsNot(
            None,
            re.match("INFO .* -> .* (.*s, cache: HIT)",
                     logging_output_lines[-1]),
            "No hit found in %r" % logging_output_lines[-1])

    def test_rewriteLine_cache_expires(self):
        # The second request for a branch misses the cache and logs this fact.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        rewriter.rewriteLine('/' + branch.unique_name + '/.bzr/README')
        self.fake_time.advance(
            config.codehosting.branch_rewrite_cache_lifetime + 1)
        rewriter.rewriteLine('/' + branch.unique_name + '/.bzr/README')
        logging_output_lines = self.getLoggerOutput(rewriter).strip().split(
            '\n')
        self.assertEqual(2, len(logging_output_lines))
        self.assertIsNot(
            None,
            re.match("INFO .* -> .* (.*s, cache: MISS)",
                     logging_output_lines[-1]),
            "No miss found in %r" % logging_output_lines[-1])

    def test_getBranchIdAndTrailingPath_cached(self):
        """When results come from cache, they should be the same."""
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        id_path = (
            branch.id,
            u'/.bzr/README',
        )
        result = rewriter._getBranchIdAndTrailingPath('/' +
                                                      branch.unique_name +
                                                      '/.bzr/README')
        self.assertEqual(id_path + ('MISS', ), result)
        result = rewriter._getBranchIdAndTrailingPath('/' +
                                                      branch.unique_name +
                                                      '/.bzr/README')
        self.assertEqual(id_path + ('HIT', ), result)

    def test_branch_id_alias_private(self):
        # Private branches are not found at all (this is for anonymous access)
        owner = self.factory.makePerson()
        branch = self.factory.makeAnyBranch(
            owner=owner, information_type=InformationType.USERDATA)
        with person_logged_in(owner):
            path = branch_id_alias(branch)
        result = self.makeRewriter()._getBranchIdAndTrailingPath(path)
        self.assertEqual((None, None, 'MISS'), result)

    def test_branch_id_alias_transitive_private(self):
        # Transitively private branches are not found at all
        # (this is for anonymous access)
        owner = self.factory.makePerson()
        private_branch = self.factory.makeAnyBranch(
            owner=owner, information_type=InformationType.USERDATA)
        branch = self.factory.makeAnyBranch(stacked_on=private_branch,
                                            owner=owner)
        with person_logged_in(owner):
            path = branch_id_alias(branch)
        result = self.makeRewriter()._getBranchIdAndTrailingPath(path)
        self.assertEqual((None, None, 'MISS'), result)
 def setUp(self):
     TestCase.setUp(self)
     self.fake_time = FakeTime(12345)
     self.logger = BufferLogger()
class TestLoggingUIFactory(TestCase):
    """Tests for `LoggingUIFactory`."""

    def setUp(self):
        TestCase.setUp(self)
        self.fake_time = FakeTime(12345)
        self.logger = BufferLogger()

    def makeLoggingUIFactory(self):
        """Make a `LoggingUIFactory` with fake time and contained output."""
        return LoggingUIFactory(
            time_source=self.fake_time.now, logger=self.logger)

    def test_first_progress_updates(self):
        # The first call to progress generates some output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.assertEqual('INFO hi\n', self.logger.getLogBuffer())

    def test_second_rapid_progress_doesnt_update(self):
        # The second of two progress calls that are less than the factory's
        # interval apart does not generate output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.fake_time.advance(factory.interval / 2)
        bar.update("there")
        self.assertEqual('INFO hi\n', self.logger.getLogBuffer())

    def test_second_slow_progress_updates(self):
        # The second of two progress calls that are more than the factory's
        # interval apart does generate output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.fake_time.advance(factory.interval * 2)
        bar.update("there")
        self.assertEqual(
            'INFO hi\n'
            'INFO there\n',
            self.logger.getLogBuffer())

    def test_first_progress_on_new_bar_updates(self):
        # The first progress on a new progress task always generates output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.fake_time.advance(factory.interval / 2)
        bar2 = factory.nested_progress_bar()
        bar2.update("there")
        self.assertEqual(
            'INFO hi\nINFO hi:there\n', self.logger.getLogBuffer())

    def test_update_with_count_formats_nicely(self):
        # When more details are passed to update, they are formatted nicely.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi", 1, 8)
        self.assertEqual('INFO hi 1/8\n', self.logger.getLogBuffer())

    def test_report_transport_activity_reports_bytes_since_last_update(self):
        # If there is no call to _progress_updated for 'interval' seconds, the
        # next call to report_transport_activity will report however many
        # bytes have been transferred since the update.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi", 1, 10)
        self.fake_time.advance(factory.interval / 2)
        # The bytes in this call will not be reported:
        factory.report_transport_activity(None, 1, 'read')
        self.fake_time.advance(factory.interval)
        bar.update("hi", 2, 10)
        self.fake_time.advance(factory.interval / 2)
        factory.report_transport_activity(None, 10, 'read')
        self.fake_time.advance(factory.interval)
        factory.report_transport_activity(None, 100, 'read')
        self.fake_time.advance(factory.interval * 2)
        # This call will cause output that does not include the transport
        # activity info.
        bar.update("hi", 3, 10)
        self.assertEqual(
            'INFO hi 1/10\n'
            'INFO hi 2/10\n'
            'INFO 110 bytes transferred | hi 2/10\n'
            'INFO hi 3/10\n',
            self.logger.getLogBuffer())

    def test_note(self):
        factory = self.makeLoggingUIFactory()
        factory.note("Banja Luka")
        self.assertEqual('INFO Banja Luka\n', self.logger.getLogBuffer())

    def test_show_error(self):
        factory = self.makeLoggingUIFactory()
        factory.show_error("Exploding Peaches")
        self.assertEqual(
            "ERROR Exploding Peaches\n", self.logger.getLogBuffer())

    def test_confirm_action(self):
        factory = self.makeLoggingUIFactory()
        self.assertTrue(factory.confirm_action(
            "How are you %(when)s?", "wellness", {"when": "today"}))

    def test_show_message(self):
        factory = self.makeLoggingUIFactory()
        factory.show_message("Peaches")
        self.assertEqual("INFO Peaches\n", self.logger.getLogBuffer())

    def test_get_username(self):
        factory = self.makeLoggingUIFactory()
        self.assertIs(
            None, factory.get_username("Who are you %(when)s?", when="today"))

    def test_get_password(self):
        factory = self.makeLoggingUIFactory()
        self.assertIs(
            None,
            factory.get_password("How is your %(drink)s", drink="coffee"))

    def test_show_warning(self):
        factory = self.makeLoggingUIFactory()
        factory.show_warning("Peaches")
        self.assertEqual("WARNING Peaches\n", self.logger.getLogBuffer())

    def test_show_warning_unicode(self):
        factory = self.makeLoggingUIFactory()
        factory.show_warning(u"Peach\xeas")
        self.assertEqual(
            "WARNING Peach\xc3\xaas\n", self.logger.getLogBuffer())

    def test_user_warning(self):
        factory = self.makeLoggingUIFactory()
        factory.show_user_warning('cross_format_fetch',
            from_format="athing", to_format="anotherthing")
        message = factory._user_warning_templates['cross_format_fetch'] % {
            "from_format": "athing",
            "to_format": "anotherthing",
            }
        self.assertEqual("WARNING %s\n" % message, self.logger.getLogBuffer())

    def test_clear_term(self):
        factory = self.makeLoggingUIFactory()
        factory.clear_term()
        self.assertEqual("", self.logger.getLogBuffer())
Esempio n. 7
0
class TestBranchFileSystemClient(TestCase):
    """Tests for `BranchFileSystemClient`."""

    run_tests_with = AsynchronousDeferredRunTest

    def setUp(self):
        super(TestBranchFileSystemClient, self).setUp()
        frontend = InMemoryFrontend()
        self.factory = frontend.getLaunchpadObjectFactory()
        self.user = self.factory.makePerson()
        self._xmlrpc_client = XMLRPCWrapper(frontend.getCodehostingEndpoint())
        self.fake_time = FakeTime(12345)

    def advanceTime(self, amount):
        """Advance the time seen by clients made by `makeClient` by 'amount'.
        """
        self.fake_time.advance(amount)

    def makeClient(self, expiry_time=None, seen_new_branch_hook=None):
        """Make a `BranchFileSystemClient`.

        The created client interacts with the InMemoryFrontend.
        """
        return BranchFileSystemClient(
            self._xmlrpc_client,
            self.user.id,
            expiry_time=expiry_time,
            seen_new_branch_hook=seen_new_branch_hook,
            _now=self.fake_time.now)

    def test_translatePath(self):
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        deferred = client.translatePath('/' + branch.unique_name)
        deferred.addCallback(
            self.assertEqual,
            (BRANCH_TRANSPORT, dict(id=branch.id, writable=False), ''))
        return deferred

    def test_get_matched_part(self):
        # We cache results based on the part of the URL that the server
        # matched. _getMatchedPart returns that part, based on the path given
        # and the returned data.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        requested_path = '/%s/a/b' % branch.unique_name
        matched_part = client._getMatchedPart(requested_path,
                                              (BRANCH_TRANSPORT, {
                                                  'id': branch.id,
                                                  'writable': False
                                              }, 'a/b'))
        self.assertEqual('/%s' % branch.unique_name, matched_part)

    def test_get_matched_part_no_trailing_slash(self):
        # _getMatchedPart always returns the absolute path to the object that
        # the server matched, even if there is no trailing slash and no
        # trailing path.
        #
        # This test is added to exercise a corner case.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        requested_path = '/%s' % branch.unique_name
        matched_part = client._getMatchedPart(requested_path,
                                              (BRANCH_TRANSPORT, {
                                                  'id': branch.id,
                                                  'writable': False
                                              }, ''))
        self.assertEqual('/%s' % branch.unique_name, matched_part)

    def test_get_matched_part_no_trailing_path(self):
        # _getMatchedPart always returns the absolute path to the object that
        # the server matched, even if there is a trailing slash and no
        # trailing path.
        #
        # This test is added to exercise a corner case.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        requested_path = '/%s/' % branch.unique_name
        matched_part = client._getMatchedPart(requested_path,
                                              (BRANCH_TRANSPORT, {
                                                  'id': branch.id,
                                                  'writable': False
                                              }, ''))
        self.assertEqual('/%s' % branch.unique_name, matched_part)

    def test_path_translation_cache(self):
        # We can retrieve data that we've added to the cache. The data we
        # retrieve looks an awful lot like the data that the endpoint sends.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        fake_data = self.factory.getUniqueString()
        client._addToCache((BRANCH_TRANSPORT, fake_data, ''),
                           '/%s' % branch.unique_name)
        result = client._getFromCache('/%s/foo/bar' % branch.unique_name)
        self.assertEqual((BRANCH_TRANSPORT, fake_data, 'foo/bar'), result)

    def test_path_translation_cache_within_expiry_time(self):
        # If the client treats cached values as having a limited lifetime,
        # repeated requests within that lifetime are served from the cache.
        branch = self.factory.makeAnyBranch()
        expiry_time = 2.0
        client = self.makeClient(expiry_time=expiry_time)
        fake_data = self.factory.getUniqueString()
        client._addToCache((BRANCH_TRANSPORT, fake_data, ''),
                           '/%s' % branch.unique_name)
        self.advanceTime(expiry_time / 2)
        result = client._getFromCache('/%s/foo/bar' % branch.unique_name)
        self.assertEqual((BRANCH_TRANSPORT, fake_data, 'foo/bar'), result)

    def test_path_translation_cache_after_expiry_time(self):
        # If the client treats cached values as having a limited lifetime, a
        # request longer than that lifetime after the first is not served from
        # the cache.
        branch = self.factory.makeAnyBranch()
        expiry_time = 2.0
        client = self.makeClient(expiry_time=expiry_time)
        fake_data = self.factory.getUniqueString()
        client._addToCache((BRANCH_TRANSPORT, fake_data, ''),
                           '/%s' % branch.unique_name)
        self.advanceTime(expiry_time * 2)
        self.assertRaises(NotInCache, client._getFromCache,
                          '/%s/foo/bar' % branch.unique_name)

    def test_path_translation_cache_respects_path_segments(self):
        # We only get a value from the cache if the cached path is a parent of
        # the requested path. Simple string prefixing is not enough. Added to
        # trap bug 308077.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        fake_data = self.factory.getUniqueString()
        client._addToCache((BRANCH_TRANSPORT, fake_data, ''),
                           '/%s' % branch.unique_name)
        self.assertRaises(NotInCache, client._getFromCache,
                          '/%s-suffix' % branch.unique_name)

    def test_not_in_cache(self):
        # _getFromCache raises an error when the given path isn't in the
        # cache.
        client = self.makeClient()
        self.assertRaises(NotInCache, client._getFromCache, "foo")

    def test_translatePath_retrieves_from_cache(self):
        # If the path already has a prefix in the cache, we use that prefix to
        # translate the path.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        # We'll store fake data in the cache to show that we get data from
        # the cache if it's present.
        fake_data = self.factory.getUniqueString()
        client._addToCache((BRANCH_TRANSPORT, fake_data, ''),
                           '/%s' % branch.unique_name)
        requested_path = '/%s/foo/bar' % branch.unique_name
        deferred = client.translatePath(requested_path)

        def path_translated((transport_type, data, trailing_path)):
            self.assertEqual(BRANCH_TRANSPORT, transport_type)
            self.assertEqual(fake_data, data)
            self.assertEqual('foo/bar', trailing_path)

        return deferred.addCallback(path_translated)

    def test_translatePath_adds_to_cache(self):
        # translatePath adds successful path translations to the cache, thus
        # allowing for future translations to be retrieved from the cache.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        deferred = client.translatePath('/' + branch.unique_name)
        deferred.addCallback(self.assertEqual,
                             client._getFromCache('/' + branch.unique_name))
        return deferred

    def test_translatePath_control_branch_cache_interaction(self):
        # We don't want the caching to make us mis-interpret paths in the
        # branch as paths into the control transport.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        self.factory.enableDefaultStackingForProduct(branch.product)
        deferred = client.translatePath('/~' + branch.owner.name + '/' +
                                        branch.product.name + '/.bzr/format')

        def call_translatePath_again(ignored):
            return client.translatePath('/' + branch.unique_name)

        def check_results((transport_type, data, trailing_path)):
            self.assertEqual(BRANCH_TRANSPORT, transport_type)

        deferred.addCallback(call_translatePath_again)
        deferred.addCallback(check_results)
        return deferred

    def test_errors_not_cached(self):
        # Don't cache failed translations. What would be the point?
        client = self.makeClient()
        deferred = client.translatePath('/foo/bar/baz')

        def translated_successfully(result):
            self.fail("Translated successfully. Expected error, got %r" %
                      result)

        def failed_translation(failure):
            self.assertRaises(NotInCache, client._getFromCache, '/foo/bar/baz')

        return deferred.addCallbacks(translated_successfully,
                                     failed_translation)

    def test_seen_new_branch_hook_called_for_new_branch(self):
        # A callable passed as the seen_new_branch_hook when constructing a
        # BranchFileSystemClient will be called with a previously unseen
        # branch's unique_name when a path for a that branch is translated for
        # the first time.
        seen_branches = []
        client = self.makeClient(seen_new_branch_hook=seen_branches.append)
        branch = self.factory.makeAnyBranch()
        client.translatePath('/' + branch.unique_name + '/trailing')
        self.assertEqual([branch.unique_name], seen_branches)

    def test_seen_new_branch_hook_called_for_each_branch(self):
        # The seen_new_branch_hook is called for a each branch that is
        # accessed.
        seen_branches = []
        client = self.makeClient(seen_new_branch_hook=seen_branches.append)
        branch1 = self.factory.makeAnyBranch()
        branch2 = self.factory.makeAnyBranch()
        client.translatePath('/' + branch1.unique_name + '/trailing')
        client.translatePath('/' + branch2.unique_name + '/trailing')
        self.assertEqual([branch1.unique_name, branch2.unique_name],
                         seen_branches)

    def test_seen_new_branch_hook_called_once_for_a_new_branch(self):
        # The seen_new_branch_hook is only called once for a given branch.
        seen_branches = []
        client = self.makeClient(seen_new_branch_hook=seen_branches.append)
        branch1 = self.factory.makeAnyBranch()
        branch2 = self.factory.makeAnyBranch()
        client.translatePath('/' + branch1.unique_name + '/trailing')
        client.translatePath('/' + branch2.unique_name + '/trailing')
        client.translatePath('/' + branch1.unique_name + '/different')
        self.assertEqual([branch1.unique_name, branch2.unique_name],
                         seen_branches)
Esempio n. 8
0
 def setUp(self):
     TestCase.setUp(self)
     self.fake_time = FakeTime(12345)
     self.logger = BufferLogger()
Esempio n. 9
0
class TestLoggingUIFactory(TestCase):
    """Tests for `LoggingUIFactory`."""
    def setUp(self):
        TestCase.setUp(self)
        self.fake_time = FakeTime(12345)
        self.logger = BufferLogger()

    def makeLoggingUIFactory(self):
        """Make a `LoggingUIFactory` with fake time and contained output."""
        return LoggingUIFactory(time_source=self.fake_time.now,
                                logger=self.logger)

    def test_first_progress_updates(self):
        # The first call to progress generates some output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.assertEqual('INFO hi\n', self.logger.getLogBuffer())

    def test_second_rapid_progress_doesnt_update(self):
        # The second of two progress calls that are less than the factory's
        # interval apart does not generate output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.fake_time.advance(factory.interval / 2)
        bar.update("there")
        self.assertEqual('INFO hi\n', self.logger.getLogBuffer())

    def test_second_slow_progress_updates(self):
        # The second of two progress calls that are more than the factory's
        # interval apart does generate output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.fake_time.advance(factory.interval * 2)
        bar.update("there")
        self.assertEqual('INFO hi\n'
                         'INFO there\n', self.logger.getLogBuffer())

    def test_first_progress_on_new_bar_updates(self):
        # The first progress on a new progress task always generates output.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi")
        self.fake_time.advance(factory.interval / 2)
        bar2 = factory.nested_progress_bar()
        bar2.update("there")
        self.assertEqual('INFO hi\nINFO hi:there\n',
                         self.logger.getLogBuffer())

    def test_update_with_count_formats_nicely(self):
        # When more details are passed to update, they are formatted nicely.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi", 1, 8)
        self.assertEqual('INFO hi 1/8\n', self.logger.getLogBuffer())

    def test_report_transport_activity_reports_bytes_since_last_update(self):
        # If there is no call to _progress_updated for 'interval' seconds, the
        # next call to report_transport_activity will report however many
        # bytes have been transferred since the update.
        factory = self.makeLoggingUIFactory()
        bar = factory.nested_progress_bar()
        bar.update("hi", 1, 10)
        self.fake_time.advance(factory.interval / 2)
        # The bytes in this call will not be reported:
        factory.report_transport_activity(None, 1, 'read')
        self.fake_time.advance(factory.interval)
        bar.update("hi", 2, 10)
        self.fake_time.advance(factory.interval / 2)
        factory.report_transport_activity(None, 10, 'read')
        self.fake_time.advance(factory.interval)
        factory.report_transport_activity(None, 100, 'read')
        self.fake_time.advance(factory.interval * 2)
        # This call will cause output that does not include the transport
        # activity info.
        bar.update("hi", 3, 10)
        self.assertEqual(
            'INFO hi 1/10\n'
            'INFO hi 2/10\n'
            'INFO 110 bytes transferred | hi 2/10\n'
            'INFO hi 3/10\n', self.logger.getLogBuffer())

    def test_note(self):
        factory = self.makeLoggingUIFactory()
        factory.note("Banja Luka")
        self.assertEqual('INFO Banja Luka\n', self.logger.getLogBuffer())

    def test_show_error(self):
        factory = self.makeLoggingUIFactory()
        factory.show_error("Exploding Peaches")
        self.assertEqual("ERROR Exploding Peaches\n",
                         self.logger.getLogBuffer())

    def test_confirm_action(self):
        factory = self.makeLoggingUIFactory()
        self.assertTrue(
            factory.confirm_action("How are you %(when)s?", "wellness",
                                   {"when": "today"}))

    def test_show_message(self):
        factory = self.makeLoggingUIFactory()
        factory.show_message("Peaches")
        self.assertEqual("INFO Peaches\n", self.logger.getLogBuffer())

    def test_get_username(self):
        factory = self.makeLoggingUIFactory()
        self.assertIs(
            None, factory.get_username("Who are you %(when)s?", when="today"))

    def test_get_password(self):
        factory = self.makeLoggingUIFactory()
        self.assertIs(
            None, factory.get_password("How is your %(drink)s",
                                       drink="coffee"))

    def test_show_warning(self):
        factory = self.makeLoggingUIFactory()
        factory.show_warning("Peaches")
        self.assertEqual("WARNING Peaches\n", self.logger.getLogBuffer())

    def test_show_warning_unicode(self):
        factory = self.makeLoggingUIFactory()
        factory.show_warning(u"Peach\xeas")
        self.assertEqual("WARNING Peach\xc3\xaas\n",
                         self.logger.getLogBuffer())

    def test_user_warning(self):
        factory = self.makeLoggingUIFactory()
        factory.show_user_warning('cross_format_fetch',
                                  from_format="athing",
                                  to_format="anotherthing")
        message = factory._user_warning_templates['cross_format_fetch'] % {
            "from_format": "athing",
            "to_format": "anotherthing",
        }
        self.assertEqual("WARNING %s\n" % message, self.logger.getLogBuffer())

    def test_clear_term(self):
        factory = self.makeLoggingUIFactory()
        factory.clear_term()
        self.assertEqual("", self.logger.getLogBuffer())
class TestBranchFileSystemClient(TestCase):
    """Tests for `BranchFileSystemClient`."""

    run_tests_with = AsynchronousDeferredRunTest

    def setUp(self):
        super(TestBranchFileSystemClient, self).setUp()
        frontend = InMemoryFrontend()
        self.factory = frontend.getLaunchpadObjectFactory()
        self.user = self.factory.makePerson()
        self._xmlrpc_client = XMLRPCWrapper(frontend.getCodehostingEndpoint())
        self.fake_time = FakeTime(12345)

    def advanceTime(self, amount):
        """Advance the time seen by clients made by `makeClient` by 'amount'.
        """
        self.fake_time.advance(amount)

    def makeClient(self, expiry_time=None, seen_new_branch_hook=None):
        """Make a `BranchFileSystemClient`.

        The created client interacts with the InMemoryFrontend.
        """
        return BranchFileSystemClient(
            self._xmlrpc_client, self.user.id, expiry_time=expiry_time,
            seen_new_branch_hook=seen_new_branch_hook,
            _now=self.fake_time.now)

    def test_translatePath(self):
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        deferred = client.translatePath('/' + branch.unique_name)
        deferred.addCallback(
            self.assertEqual,
            (BRANCH_TRANSPORT, dict(id=branch.id, writable=False), ''))
        return deferred

    def test_get_matched_part(self):
        # We cache results based on the part of the URL that the server
        # matched. _getMatchedPart returns that part, based on the path given
        # and the returned data.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        requested_path = '/%s/a/b' % branch.unique_name
        matched_part = client._getMatchedPart(
            requested_path,
            (BRANCH_TRANSPORT, {'id': branch.id, 'writable': False}, 'a/b'))
        self.assertEqual('/%s' % branch.unique_name, matched_part)

    def test_get_matched_part_no_trailing_slash(self):
        # _getMatchedPart always returns the absolute path to the object that
        # the server matched, even if there is no trailing slash and no
        # trailing path.
        #
        # This test is added to exercise a corner case.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        requested_path = '/%s' % branch.unique_name
        matched_part = client._getMatchedPart(
            requested_path,
            (BRANCH_TRANSPORT, {'id': branch.id, 'writable': False}, ''))
        self.assertEqual('/%s' % branch.unique_name, matched_part)

    def test_get_matched_part_no_trailing_path(self):
        # _getMatchedPart always returns the absolute path to the object that
        # the server matched, even if there is a trailing slash and no
        # trailing path.
        #
        # This test is added to exercise a corner case.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        requested_path = '/%s/' % branch.unique_name
        matched_part = client._getMatchedPart(
            requested_path,
            (BRANCH_TRANSPORT, {'id': branch.id, 'writable': False}, ''))
        self.assertEqual('/%s' % branch.unique_name, matched_part)

    def test_path_translation_cache(self):
        # We can retrieve data that we've added to the cache. The data we
        # retrieve looks an awful lot like the data that the endpoint sends.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        fake_data = self.factory.getUniqueString()
        client._addToCache(
            (BRANCH_TRANSPORT, fake_data, ''), '/%s' % branch.unique_name)
        result = client._getFromCache('/%s/foo/bar' % branch.unique_name)
        self.assertEqual(
            (BRANCH_TRANSPORT, fake_data, 'foo/bar'), result)

    def test_path_translation_cache_within_expiry_time(self):
        # If the client treats cached values as having a limited lifetime,
        # repeated requests within that lifetime are served from the cache.
        branch = self.factory.makeAnyBranch()
        expiry_time = 2.0
        client = self.makeClient(expiry_time=expiry_time)
        fake_data = self.factory.getUniqueString()
        client._addToCache(
            (BRANCH_TRANSPORT, fake_data, ''), '/%s' % branch.unique_name)
        self.advanceTime(expiry_time/2)
        result = client._getFromCache('/%s/foo/bar' % branch.unique_name)
        self.assertEqual(
            (BRANCH_TRANSPORT, fake_data, 'foo/bar'), result)

    def test_path_translation_cache_after_expiry_time(self):
        # If the client treats cached values as having a limited lifetime, a
        # request longer than that lifetime after the first is not served from
        # the cache.
        branch = self.factory.makeAnyBranch()
        expiry_time = 2.0
        client = self.makeClient(expiry_time=expiry_time)
        fake_data = self.factory.getUniqueString()
        client._addToCache(
            (BRANCH_TRANSPORT, fake_data, ''), '/%s' % branch.unique_name)
        self.advanceTime(expiry_time*2)
        self.assertRaises(NotInCache, client._getFromCache,
                          '/%s/foo/bar' % branch.unique_name)

    def test_path_translation_cache_respects_path_segments(self):
        # We only get a value from the cache if the cached path is a parent of
        # the requested path. Simple string prefixing is not enough. Added to
        # trap bug 308077.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        fake_data = self.factory.getUniqueString()
        client._addToCache(
            (BRANCH_TRANSPORT, fake_data, ''), '/%s' % branch.unique_name)
        self.assertRaises(
            NotInCache,
            client._getFromCache, '/%s-suffix' % branch.unique_name)

    def test_not_in_cache(self):
        # _getFromCache raises an error when the given path isn't in the
        # cache.
        client = self.makeClient()
        self.assertRaises(
            NotInCache, client._getFromCache, "foo")

    def test_translatePath_retrieves_from_cache(self):
        # If the path already has a prefix in the cache, we use that prefix to
        # translate the path.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        # We'll store fake data in the cache to show that we get data from
        # the cache if it's present.
        fake_data = self.factory.getUniqueString()
        client._addToCache(
            (BRANCH_TRANSPORT, fake_data, ''), '/%s' % branch.unique_name)
        requested_path = '/%s/foo/bar' % branch.unique_name
        deferred = client.translatePath(requested_path)
        def path_translated((transport_type, data, trailing_path)):
            self.assertEqual(BRANCH_TRANSPORT, transport_type)
            self.assertEqual(fake_data, data)
            self.assertEqual('foo/bar', trailing_path)
        return deferred.addCallback(path_translated)

    def test_translatePath_adds_to_cache(self):
        # translatePath adds successful path translations to the cache, thus
        # allowing for future translations to be retrieved from the cache.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        deferred = client.translatePath('/' + branch.unique_name)
        deferred.addCallback(
            self.assertEqual,
            client._getFromCache('/' + branch.unique_name))
        return deferred

    def test_translatePath_control_branch_cache_interaction(self):
        # We don't want the caching to make us mis-interpret paths in the
        # branch as paths into the control transport.
        branch = self.factory.makeAnyBranch()
        client = self.makeClient()
        self.factory.enableDefaultStackingForProduct(branch.product)
        deferred = client.translatePath(
            '/~' + branch.owner.name + '/' + branch.product.name +
            '/.bzr/format')
        def call_translatePath_again(ignored):
            return client.translatePath('/' + branch.unique_name)
        def check_results((transport_type, data, trailing_path)):
            self.assertEqual(BRANCH_TRANSPORT, transport_type)
        deferred.addCallback(call_translatePath_again)
        deferred.addCallback(check_results)
        return deferred

    def test_errors_not_cached(self):
        # Don't cache failed translations. What would be the point?
        client = self.makeClient()
        deferred = client.translatePath('/foo/bar/baz')
        def translated_successfully(result):
            self.fail(
                "Translated successfully. Expected error, got %r" % result)
        def failed_translation(failure):
            self.assertRaises(
                NotInCache, client._getFromCache, '/foo/bar/baz')
        return deferred.addCallbacks(
            translated_successfully, failed_translation)

    def test_seen_new_branch_hook_called_for_new_branch(self):
        # A callable passed as the seen_new_branch_hook when constructing a
        # BranchFileSystemClient will be called with a previously unseen
        # branch's unique_name when a path for a that branch is translated for
        # the first time.
        seen_branches = []
        client = self.makeClient(seen_new_branch_hook=seen_branches.append)
        branch = self.factory.makeAnyBranch()
        client.translatePath('/' + branch.unique_name + '/trailing')
        self.assertEqual([branch.unique_name], seen_branches)

    def test_seen_new_branch_hook_called_for_each_branch(self):
        # The seen_new_branch_hook is called for a each branch that is
        # accessed.
        seen_branches = []
        client = self.makeClient(seen_new_branch_hook=seen_branches.append)
        branch1 = self.factory.makeAnyBranch()
        branch2 = self.factory.makeAnyBranch()
        client.translatePath('/' + branch1.unique_name + '/trailing')
        client.translatePath('/' + branch2.unique_name + '/trailing')
        self.assertEqual(
            [branch1.unique_name, branch2.unique_name], seen_branches)

    def test_seen_new_branch_hook_called_once_for_a_new_branch(self):
        # The seen_new_branch_hook is only called once for a given branch.
        seen_branches = []
        client = self.makeClient(seen_new_branch_hook=seen_branches.append)
        branch1 = self.factory.makeAnyBranch()
        branch2 = self.factory.makeAnyBranch()
        client.translatePath('/' + branch1.unique_name + '/trailing')
        client.translatePath('/' + branch2.unique_name + '/trailing')
        client.translatePath('/' + branch1.unique_name + '/different')
        self.assertEqual(
            [branch1.unique_name, branch2.unique_name], seen_branches)
Esempio n. 11
0
 def setUp(self):
     super(TestBranchRewriter, self).setUp()
     self.fake_time = FakeTime(0)
Esempio n. 12
0
class TestBranchRewriter(TestCaseWithFactory):

    layer = DatabaseFunctionalLayer

    def setUp(self):
        super(TestBranchRewriter, self).setUp()
        self.fake_time = FakeTime(0)

    def makeRewriter(self):
        return BranchRewriter(BufferLogger(), self.fake_time.now)

    def getLoggerOutput(self, rewriter):
        return rewriter.logger.getLogBuffer()

    def test_rewriteLine_found_dot_bzr(self):
        # Requests for /$branch_name/.bzr/... are redirected to where the
        # branches are served from by ID.
        rewriter = self.makeRewriter()
        branches = [
            self.factory.makeProductBranch(),
            self.factory.makePersonalBranch(),
            self.factory.makePackageBranch(),
        ]
        transaction.commit()
        output = [rewriter.rewriteLine("/%s/.bzr/README" % branch.unique_name) for branch in branches]
        expected = [
            "file:///var/tmp/bazaar.launchpad.dev/mirrors/%s/.bzr/README" % branch_id_to_path(branch.id)
            for branch in branches
        ]
        self.assertEqual(expected, output)

    def test_rewriteLine_found_not_dot_bzr(self):
        # Requests for /$branch_name/... that are not to .bzr directories are
        # redirected to codebrowse.
        rewriter = self.makeRewriter()
        branches = [
            self.factory.makeProductBranch(),
            self.factory.makePersonalBranch(),
            self.factory.makePackageBranch(),
        ]
        transaction.commit()
        output = [rewriter.rewriteLine("/%s/changes" % branch.unique_name) for branch in branches]
        expected = ["http://localhost:8080/%s/changes" % branch.unique_name for branch in branches]
        self.assertEqual(expected, output)

    def test_rewriteLine_private(self):
        # All requests for /$branch_name/... for private branches are
        # rewritten to codebrowse, which will then redirect them to https and
        # handle them there.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch(information_type=InformationType.USERDATA)
        unique_name = removeSecurityProxy(branch).unique_name
        transaction.commit()
        output = [rewriter.rewriteLine("/%s/changes" % unique_name), rewriter.rewriteLine("/%s/.bzr" % unique_name)]
        self.assertEqual(
            ["http://localhost:8080/%s/changes" % unique_name, "http://localhost:8080/%s/.bzr" % unique_name], output
        )

    def test_rewriteLine_id_alias_found_dot_bzr(self):
        # Requests for /+branch-id/$id/.bzr/... are redirected to where the
        # branches are served from by ID if they are public.
        rewriter = self.makeRewriter()
        branches = [
            self.factory.makeProductBranch(),
            self.factory.makePersonalBranch(),
            self.factory.makePackageBranch(),
        ]
        transaction.commit()
        output = [rewriter.rewriteLine("%s/.bzr/README" % branch_id_alias(branch)) for branch in branches]
        expected = [
            "file:///var/tmp/bazaar.launchpad.dev/mirrors/%s/.bzr/README" % branch_id_to_path(branch.id)
            for branch in branches
        ]
        self.assertEqual(expected, output)

    def test_rewriteLine_id_alias_private(self):
        # All requests for /+branch-id/$id/... for private branches return
        # 'NULL'.  This is translated by apache to a 404.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch(information_type=InformationType.USERDATA)
        path = branch_id_alias(removeSecurityProxy(branch))
        transaction.commit()
        output = [rewriter.rewriteLine("%s/changes" % path), rewriter.rewriteLine("%s/.bzr" % path)]
        self.assertEqual(["NULL", "NULL"], output)

    def test_rewriteLine_id_alias_logs_cache_hit(self):
        # The second request for a branch using the alias hits the cache.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        path = "%s/.bzr/README" % branch_id_alias(branch)
        rewriter.rewriteLine(path)
        rewriter.rewriteLine(path)
        logging_output_lines = self.getLoggerOutput(rewriter).strip().split("\n")
        self.assertEqual(2, len(logging_output_lines))
        self.assertIsNot(
            None,
            re.match("INFO .* -> .* (.*s, cache: HIT)", logging_output_lines[-1]),
            "No hit found in %r" % logging_output_lines[-1],
        )

    def test_rewriteLine_static(self):
        # Requests to /static are rewritten to codebrowse urls.
        rewriter = self.makeRewriter()
        output = rewriter.rewriteLine("/static/foo")
        self.assertEqual("http://localhost:8080/static/foo", output)

    def test_rewriteLine_not_found(self):
        # If the request does not map to a branch, we redirect it to
        # codebrowse as it can generate a 404.
        rewriter = self.makeRewriter()
        not_found_path = "/~nouser/noproduct"
        output = rewriter.rewriteLine(not_found_path)
        self.assertEqual("http://localhost:8080%s" % not_found_path, output)

    def test_rewriteLine_logs_cache_miss(self):
        # The first request for a branch misses the cache and logs this fact.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        rewriter.rewriteLine("/" + branch.unique_name + "/.bzr/README")
        logging_output = self.getLoggerOutput(rewriter)
        self.assertIsNot(
            None, re.match("INFO .* -> .* (.*s, cache: MISS)", logging_output), "No miss found in %r" % logging_output
        )

    def test_rewriteLine_logs_cache_hit(self):
        # The second request for a branch misses the cache and logs this fact.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        rewriter.rewriteLine("/" + branch.unique_name + "/.bzr/README")
        rewriter.rewriteLine("/" + branch.unique_name + "/.bzr/README")
        logging_output_lines = self.getLoggerOutput(rewriter).strip().split("\n")
        self.assertEqual(2, len(logging_output_lines))
        self.assertIsNot(
            None,
            re.match("INFO .* -> .* (.*s, cache: HIT)", logging_output_lines[-1]),
            "No hit found in %r" % logging_output_lines[-1],
        )

    def test_rewriteLine_cache_expires(self):
        # The second request for a branch misses the cache and logs this fact.
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        rewriter.rewriteLine("/" + branch.unique_name + "/.bzr/README")
        self.fake_time.advance(config.codehosting.branch_rewrite_cache_lifetime + 1)
        rewriter.rewriteLine("/" + branch.unique_name + "/.bzr/README")
        logging_output_lines = self.getLoggerOutput(rewriter).strip().split("\n")
        self.assertEqual(2, len(logging_output_lines))
        self.assertIsNot(
            None,
            re.match("INFO .* -> .* (.*s, cache: MISS)", logging_output_lines[-1]),
            "No miss found in %r" % logging_output_lines[-1],
        )

    def test_getBranchIdAndTrailingPath_cached(self):
        """When results come from cache, they should be the same."""
        rewriter = self.makeRewriter()
        branch = self.factory.makeAnyBranch()
        transaction.commit()
        id_path = (branch.id, u"/.bzr/README")
        result = rewriter._getBranchIdAndTrailingPath("/" + branch.unique_name + "/.bzr/README")
        self.assertEqual(id_path + ("MISS",), result)
        result = rewriter._getBranchIdAndTrailingPath("/" + branch.unique_name + "/.bzr/README")
        self.assertEqual(id_path + ("HIT",), result)

    def test_branch_id_alias_private(self):
        # Private branches are not found at all (this is for anonymous access)
        owner = self.factory.makePerson()
        branch = self.factory.makeAnyBranch(owner=owner, information_type=InformationType.USERDATA)
        with person_logged_in(owner):
            path = branch_id_alias(branch)
        result = self.makeRewriter()._getBranchIdAndTrailingPath(path)
        self.assertEqual((None, None, "MISS"), result)

    def test_branch_id_alias_transitive_private(self):
        # Transitively private branches are not found at all
        # (this is for anonymous access)
        owner = self.factory.makePerson()
        private_branch = self.factory.makeAnyBranch(owner=owner, information_type=InformationType.USERDATA)
        branch = self.factory.makeAnyBranch(stacked_on=private_branch, owner=owner)
        with person_logged_in(owner):
            path = branch_id_alias(branch)
        result = self.makeRewriter()._getBranchIdAndTrailingPath(path)
        self.assertEqual((None, None, "MISS"), result)