launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24134
[Merge] ~cjwatson/launchpad:faster-bugs-webservice-tests into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:faster-bugs-webservice-tests into launchpad:master.
Commit message:
Stop using launchpadlib in bugs webservice tests
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/375798
Port the bugs webservice tests to use in-process webservice calls rather than launchpadlib and AppServerLayer. While the code is a bit longer as a result, it's easier to debug and substantially faster: this change takes the test time for these test suites from 106 seconds to 22 seconds on my laptop.
Similarly, I downgraded a couple of bug subscription filter test suites from LaunchpadFunctionalLayer to DatabaseFunctionalLayer, since they didn't use anything extra from the more sophisticated layer.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:faster-bugs-webservice-tests into launchpad:master.
diff --git a/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py b/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py
index f43e922..30e6cca 100644
--- a/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py
+++ b/lib/lp/bugs/browser/tests/test_bugattachment_file_access.py
@@ -1,15 +1,16 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
import re
-from urlparse import (
+
+import requests
+from six.moves.urllib.parse import (
parse_qs,
urlparse,
+ urlunparse,
)
-
-from lazr.restfulclient.errors import NotFound as RestfulNotFound
import transaction
from zope.component import (
getMultiAdapter,
@@ -17,24 +18,27 @@ from zope.component import (
)
from zope.publisher.interfaces import NotFound
from zope.security.interfaces import Unauthorized
-from zope.security.management import endInteraction
from lp.bugs.browser.bugattachment import BugAttachmentFileNavigation
+from lp.services.config import config
from lp.services.librarian.interfaces import ILibraryFileAliasWithParent
-from lp.services.webapp.interfaces import ILaunchBag
+from lp.services.webapp.interfaces import (
+ ILaunchBag,
+ OAuthPermission,
+ )
from lp.services.webapp.publisher import RedirectionView
from lp.services.webapp.servers import LaunchpadTestRequest
from lp.testing import (
- launchpadlib_for,
+ api_url,
login_person,
+ logout,
TestCaseWithFactory,
- ws_object,
)
-from lp.testing.layers import (
- AppServerLayer,
- LaunchpadFunctionalLayer,
+from lp.testing.layers import LaunchpadFunctionalLayer
+from lp.testing.pages import (
+ LaunchpadWebServiceCaller,
+ webservice_for_person,
)
-from lp.testing.pages import LaunchpadWebServiceCaller
class TestAccessToBugAttachmentFiles(TestCaseWithFactory):
@@ -119,7 +123,7 @@ class TestAccessToBugAttachmentFiles(TestCaseWithFactory):
class TestWebserviceAccessToBugAttachmentFiles(TestCaseWithFactory):
"""Tests access to bug attachments via the webservice."""
- layer = AppServerLayer
+ layer = LaunchpadFunctionalLayer
def setUp(self):
super(TestWebserviceAccessToBugAttachmentFiles, self).setUp()
@@ -127,48 +131,41 @@ class TestWebserviceAccessToBugAttachmentFiles(TestCaseWithFactory):
getUtility(ILaunchBag).clear()
login_person(self.bug_owner)
self.bug = self.factory.makeBug(owner=self.bug_owner)
- self.bugattachment = self.factory.makeBugAttachment(
+ self.factory.makeBugAttachment(
bug=self.bug, filename='foo.txt', data='file content')
+ self.bug_url = api_url(self.bug)
def test_anon_access_to_public_bug_attachment(self):
# Attachments of public bugs can be accessed by anonymous users.
- #
- # Need to endInteraction() because launchpadlib_for_anonymous() will
- # setup a new one.
- endInteraction()
- launchpad = launchpadlib_for('test', None, version='devel')
- ws_bug = ws_object(launchpad, self.bug)
- ws_bugattachment = ws_bug.attachments[0]
- self.assertEqual(
- 'file content', ws_bugattachment.data.open().read())
+ logout()
+ webservice = LaunchpadWebServiceCaller(
+ 'test', '', default_api_version='devel')
+ ws_bug = self.getWebserviceJSON(webservice, self.bug_url)
+ ws_bug_attachment = self.getWebserviceJSON(
+ webservice, ws_bug['attachments_collection_link'])['entries'][0]
+ response = webservice.get(ws_bug_attachment['data_link'])
+ self.assertEqual(303, response.status)
+ response = requests.get(response.getHeader('Location'))
+ response.raise_for_status()
+ self.assertEqual(b'file content', response.content)
def test_user_access_to_private_bug_attachment(self):
# Users having access to private bugs can also read attachments
# of these bugs.
self.bug.setPrivate(True, self.bug_owner)
other_user = self.factory.makePerson()
- launchpad = launchpadlib_for('test', self.bug_owner, version='devel')
- ws_bug = ws_object(launchpad, self.bug)
- ws_bugattachment = ws_bug.attachments[0]
-
- # The attachment contains a link to a HostedBytes resource;
- # the response to a GET request of this URL is a redirect to a
- # Librarian URL. We cannot simply access these Librarian URLs
- # for restricted Librarian files because the host name used in
- # the URLs is different for each file, and our test envireonment
- # does not support wildcard DNS, and because the Launchpadlib
- # browser automatically follows redirects.
- # LaunchpadWebServiceCaller, on the other hand, gives us
- # access to a raw HTTPResonse object.
- webservice = LaunchpadWebServiceCaller(
- 'launchpad-library', 'salgado-change-anything')
- response = webservice.get(ws_bugattachment.data._wadl_resource._url)
+ webservice = webservice_for_person(
+ self.bug_owner, permission=OAuthPermission.READ_PRIVATE)
+ ws_bug = self.getWebserviceJSON(webservice, self.bug_url)
+ ws_bug_attachment = self.getWebserviceJSON(
+ webservice, ws_bug['attachments_collection_link'])['entries'][0]
+ response = webservice.get(ws_bug_attachment['data_link'])
self.assertEqual(303, response.status)
# The Librarian URL has, for our test case, the form
# "https://NNNN.restricted.launchpad.test:PORT/NNNN/foo.txt?token=..."
# where NNNN and PORT are integers.
- parsed_url = urlparse(response.getHeader('location'))
+ parsed_url = urlparse(response.getHeader('Location'))
self.assertEqual('https', parsed_url.scheme)
mo = re.search(
r'^i\d+\.restricted\..+:\d+$', parsed_url.netloc)
@@ -178,10 +175,20 @@ class TestWebserviceAccessToBugAttachmentFiles(TestCaseWithFactory):
params = parse_qs(parsed_url.query)
self.assertEqual(['token'], params.keys())
+ # Our test environment does not support wildcard DNS. Work around
+ # this.
+ librarian_netloc = '%s:%d' % (
+ config.librarian.download_host, config.librarian.download_port)
+ url = urlunparse(
+ ('http', librarian_netloc, parsed_url.path, parsed_url.params,
+ parsed_url.query, parsed_url.fragment))
+ response = requests.get(url, headers={'Host': parsed_url.netloc})
+ response.raise_for_status()
+ self.assertEqual(b'file content', response.content)
+
# If a user which cannot access the private bug itself tries to
- # to access the attachment, an NotFound error is raised.
- other_launchpad = launchpadlib_for(
- 'test_unauthenticated', other_user, version='devel')
- self.assertRaises(
- RestfulNotFound, other_launchpad._browser.get,
- ws_bugattachment.data._wadl_resource._url)
+ # to access the attachment, we deny its existence.
+ other_webservice = webservice_for_person(
+ other_user, permission=OAuthPermission.READ_PRIVATE)
+ response = other_webservice.get(ws_bug_attachment['data_link'])
+ self.assertEqual(404, response.status)
diff --git a/lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py b/lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py
index cd5cacb..1ae3b1e 100644
--- a/lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py
+++ b/lib/lp/bugs/browser/tests/test_bugsubscriptionfilter.py
@@ -1,18 +1,15 @@
-# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for bug subscription filter browser code."""
__metaclass__ = type
-from functools import partial
+import json
from urlparse import urlparse
-from lazr.restfulclient.errors import BadRequest
from lxml import html
-from storm.exceptions import LostObjectError
from testtools.matchers import StartsWith
-import transaction
from lp.app.enums import InformationType
from lp.bugs.browser.structuralsubscription import (
@@ -23,21 +20,19 @@ from lp.bugs.interfaces.bugtask import (
BugTaskImportance,
BugTaskStatus,
)
+from lp.services.webapp.interfaces import OAuthPermission
from lp.services.webapp.publisher import canonical_url
from lp.services.webapp.servers import LaunchpadTestRequest
from lp.testing import (
anonymous_logged_in,
+ api_url,
login_person,
normalize_whitespace,
person_logged_in,
TestCaseWithFactory,
- ws_object,
- )
-from lp.testing.layers import (
- AppServerLayer,
- DatabaseFunctionalLayer,
- LaunchpadFunctionalLayer,
)
+from lp.testing.layers import DatabaseFunctionalLayer
+from lp.testing.pages import webservice_for_person
from lp.testing.views import create_initialized_view
@@ -53,12 +48,14 @@ class TestBugSubscriptionFilterBase:
self.owner, self.owner)
self.initial_filter = self.subscription.bug_filters.one()
self.subscription_filter = self.subscription.newBugFilter()
+ self.subscription_url = api_url(self.subscription)
+ self.subscription_filter_url = api_url(self.subscription_filter)
class TestBugSubscriptionFilterNavigation(
TestBugSubscriptionFilterBase, TestCaseWithFactory):
- layer = LaunchpadFunctionalLayer
+ layer = DatabaseFunctionalLayer
def test_canonical_url(self):
url = urlparse(canonical_url(self.subscription_filter))
@@ -80,35 +77,34 @@ class TestBugSubscriptionFilterNavigation(
class TestBugSubscriptionFilterAPI(
TestBugSubscriptionFilterBase, TestCaseWithFactory):
- layer = AppServerLayer
+ layer = DatabaseFunctionalLayer
def test_visible_attributes(self):
# Bug subscription filters are not private objects. All attributes are
# visible to everyone.
- transaction.commit()
- # Create a service for a new person.
- service = self.factory.makeLaunchpadService()
- get_ws_object = partial(ws_object, service)
- ws_subscription = get_ws_object(self.subscription)
- ws_subscription_filter = get_ws_object(self.subscription_filter)
+ webservice = webservice_for_person(self.factory.makePerson())
+ ws_subscription = self.getWebserviceJSON(
+ webservice, self.subscription_url)
+ ws_subscription_filter = self.getWebserviceJSON(
+ webservice, self.subscription_filter_url)
self.assertEqual(
- ws_subscription.self_link,
- ws_subscription_filter.structural_subscription_link)
+ ws_subscription["self_link"],
+ ws_subscription_filter["structural_subscription_link"])
self.assertEqual(
self.subscription_filter.find_all_tags,
- ws_subscription_filter.find_all_tags)
+ ws_subscription_filter["find_all_tags"])
self.assertEqual(
self.subscription_filter.description,
- ws_subscription_filter.description)
+ ws_subscription_filter["description"])
self.assertEqual(
list(self.subscription_filter.statuses),
- ws_subscription_filter.statuses)
+ ws_subscription_filter["statuses"])
self.assertEqual(
list(self.subscription_filter.importances),
- ws_subscription_filter.importances)
+ ws_subscription_filter["importances"])
self.assertEqual(
list(self.subscription_filter.tags),
- ws_subscription_filter.tags)
+ ws_subscription_filter["tags"])
def test_structural_subscription_cannot_be_modified(self):
# Bug filters cannot be moved from one structural subscription to
@@ -117,15 +113,14 @@ class TestBugSubscriptionFilterAPI(
user = self.factory.makePerson(name=u"baz")
with person_logged_in(self.owner):
user_subscription = self.structure.addBugSubscription(user, user)
- transaction.commit()
- # Create a service for the structure owner.
- service = self.factory.makeLaunchpadService(self.owner)
- get_ws_object = partial(ws_object, service)
- ws_user_subscription = get_ws_object(user_subscription)
- ws_subscription_filter = get_ws_object(self.subscription_filter)
- ws_subscription_filter.structural_subscription = ws_user_subscription
- error = self.assertRaises(BadRequest, ws_subscription_filter.lp_save)
- self.assertEqual(400, error.response.status)
+ user_subscription_url = api_url(user_subscription)
+ webservice = webservice_for_person(
+ self.owner, permission=OAuthPermission.WRITE_PUBLIC)
+ response = webservice.patch(
+ self.subscription_filter_url, "application/json",
+ json.dumps(
+ {"structural_subscription_link": user_subscription_url}))
+ self.assertEqual(400, response.status)
self.assertEqual(
self.subscription,
self.subscription_filter.structural_subscription)
@@ -134,14 +129,12 @@ class TestBugSubscriptionFilterAPI(
class TestBugSubscriptionFilterAPIModifications(
TestBugSubscriptionFilterBase, TestCaseWithFactory):
- layer = AppServerLayer
+ layer = DatabaseFunctionalLayer
def setUp(self):
super(TestBugSubscriptionFilterAPIModifications, self).setUp()
- transaction.commit()
- self.service = self.factory.makeLaunchpadService(self.owner)
- self.ws_subscription_filter = ws_object(
- self.service, self.subscription_filter)
+ self.webservice = webservice_for_person(
+ self.owner, permission=OAuthPermission.WRITE_PUBLIC)
def test_modify_tags_fields(self):
# Two tags-related fields - find_all_tags and tags - can be
@@ -154,11 +147,14 @@ class TestBugSubscriptionFilterAPIModifications(
self.assertFalse(self.subscription_filter.exclude_any_tags)
self.assertEqual(set(), self.subscription_filter.tags)
- # Modify, save, and start a new transaction.
- self.ws_subscription_filter.find_all_tags = True
- self.ws_subscription_filter.tags = ["foo", "-bar", "*", "-*"]
- self.ws_subscription_filter.lp_save()
- transaction.begin()
+ # Apply changes.
+ response = self.webservice.patch(
+ self.subscription_filter_url, "application/json",
+ json.dumps({
+ "find_all_tags": True,
+ "tags": ["foo", "-bar", "*", "-*"],
+ }))
+ self.assertEqual(209, response.status)
# Updated state.
self.assertTrue(self.subscription_filter.find_all_tags)
@@ -170,13 +166,13 @@ class TestBugSubscriptionFilterAPIModifications(
def test_modify_description(self):
# The description can be modified.
- self.assertEqual(
- None, self.subscription_filter.description)
+ self.assertIsNone(self.subscription_filter.description)
- # Modify, save, and start a new transaction.
- self.ws_subscription_filter.description = u"It's late."
- self.ws_subscription_filter.lp_save()
- transaction.begin()
+ # Apply changes.
+ response = self.webservice.patch(
+ self.subscription_filter_url, "application/json",
+ json.dumps({"description": u"It's late."}))
+ self.assertEqual(209, response.status)
# Updated state.
self.assertEqual(
@@ -186,10 +182,11 @@ class TestBugSubscriptionFilterAPIModifications(
# The statuses field can be modified.
self.assertEqual(set(), self.subscription_filter.statuses)
- # Modify, save, and start a new transaction.
- self.ws_subscription_filter.statuses = ["New", "Triaged"]
- self.ws_subscription_filter.lp_save()
- transaction.begin()
+ # Apply changes.
+ response = self.webservice.patch(
+ self.subscription_filter_url, "application/json",
+ json.dumps({"statuses": ["New", "Triaged"]}))
+ self.assertEqual(209, response.status)
# Updated state.
self.assertEqual(
@@ -200,10 +197,11 @@ class TestBugSubscriptionFilterAPIModifications(
# The importances field can be modified.
self.assertEqual(set(), self.subscription_filter.importances)
- # Modify, save, and start a new transaction.
- self.ws_subscription_filter.importances = ["Low", "High"]
- self.ws_subscription_filter.lp_save()
- transaction.begin()
+ # Apply changes.
+ response = self.webservice.patch(
+ self.subscription_filter_url, "application/json",
+ json.dumps({"importances": ["Low", "High"]}))
+ self.assertEqual(209, response.status)
# Updated state.
self.assertEqual(
@@ -212,11 +210,13 @@ class TestBugSubscriptionFilterAPIModifications(
def test_delete(self):
# Subscription filters can be deleted.
- self.ws_subscription_filter.lp_delete()
- transaction.begin()
- self.assertRaises(
- LostObjectError, getattr, self.subscription_filter,
- "find_all_tags")
+ self.assertContentEqual(
+ [self.initial_filter, self.subscription_filter],
+ self.subscription.bug_filters)
+ response = self.webservice.delete(self.subscription_filter_url)
+ self.assertEqual(200, response.status)
+ self.assertContentEqual(
+ [self.initial_filter], self.subscription.bug_filters)
class TestBugSubscriptionFilterView(
@@ -489,7 +489,7 @@ class TestBugSubscriptionFilterEditView(
class TestBugSubscriptionFilterAdvancedFeatures(TestCaseWithFactory):
"""A base class for testing advanced structural subscription features."""
- layer = LaunchpadFunctionalLayer
+ layer = DatabaseFunctionalLayer
def setUp(self):
super(TestBugSubscriptionFilterAdvancedFeatures, self).setUp()
diff --git a/lib/lp/bugs/browser/tests/test_structuralsubscription.py b/lib/lp/bugs/browser/tests/test_structuralsubscription.py
index db341b5..ff2b160 100644
--- a/lib/lp/bugs/browser/tests/test_structuralsubscription.py
+++ b/lib/lp/bugs/browser/tests/test_structuralsubscription.py
@@ -1,11 +1,10 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for structural subscription traversal."""
from urlparse import urlparse
-import transaction
from zope.publisher.interfaces import NotFound
from lp.registry.browser.distribution import DistributionNavigation
@@ -17,19 +16,18 @@ from lp.registry.browser.milestone import MilestoneNavigation
from lp.registry.browser.product import ProductNavigation
from lp.registry.browser.productseries import ProductSeriesNavigation
from lp.registry.browser.project import ProjectNavigation
+from lp.services.webapp.interfaces import OAuthPermission
from lp.services.webapp.publisher import canonical_url
from lp.testing import (
+ api_url,
FakeLaunchpadRequest,
login,
logout,
person_logged_in,
TestCaseWithFactory,
- ws_object,
- )
-from lp.testing.layers import (
- AppServerLayer,
- DatabaseFunctionalLayer,
)
+from lp.testing.layers import DatabaseFunctionalLayer
+from lp.testing.pages import webservice_for_person
from lp.testing.views import create_initialized_view
@@ -217,7 +215,7 @@ class TestSourcePackageStructuralSubscribersPortletView(
class TestStructuralSubscriptionAPI(TestCaseWithFactory):
- layer = AppServerLayer
+ layer = DatabaseFunctionalLayer
def setUp(self):
super(TestStructuralSubscriptionAPI, self).setUp()
@@ -228,40 +226,59 @@ class TestStructuralSubscriptionAPI(TestCaseWithFactory):
self.subscription = self.structure.addBugSubscription(
self.owner, self.owner)
self.initial_filter = self.subscription.bug_filters[0]
- transaction.commit()
- self.service = self.factory.makeLaunchpadService(self.owner)
- self.ws_subscription = ws_object(self.service, self.subscription)
- self.ws_subscription_filter = ws_object(
- self.service, self.initial_filter)
+ self.subscription_url = api_url(self.subscription)
+ self.initial_filter_url = api_url(self.initial_filter)
+ self.webservice = webservice_for_person(
+ self.owner, permission=OAuthPermission.WRITE_PUBLIC)
def test_newBugFilter(self):
# New bug subscription filters can be created with newBugFilter().
- ws_subscription_filter = self.ws_subscription.newBugFilter()
+ ws_subscription = self.getWebserviceJSON(
+ self.webservice, self.subscription_url)
+ response = self.webservice.named_post(
+ self.subscription_url, "newBugFilter")
+ self.assertEqual(201, response.status)
+ ws_subscription_filter = self.getWebserviceJSON(
+ self.webservice, response.getHeader("Location"))
self.assertEqual(
"bug_subscription_filter",
- urlparse(ws_subscription_filter.resource_type_link).fragment)
+ urlparse(ws_subscription_filter["resource_type_link"]).fragment)
self.assertEqual(
- ws_subscription_filter.structural_subscription.self_link,
- self.ws_subscription.self_link)
+ ws_subscription["self_link"],
+ ws_subscription_filter["structural_subscription_link"])
def test_bug_filters(self):
# The bug_filters property is a collection of IBugSubscriptionFilter
# instances previously created by newBugFilter().
- bug_filter_links = lambda: set(
- bug_filter.self_link for bug_filter in (
- self.ws_subscription.bug_filters))
- initial_filter_link = self.ws_subscription_filter.self_link
+ ws_subscription = self.getWebserviceJSON(
+ self.webservice, self.subscription_url)
+ ws_initial_filter = self.getWebserviceJSON(
+ self.webservice, self.initial_filter_url)
+
+ def bug_filter_links():
+ ws_bug_filters = self.getWebserviceJSON(
+ self.webservice,
+ ws_subscription["bug_filters_collection_link"])
+ return {entry["self_link"] for entry in ws_bug_filters["entries"]}
+
+ initial_filter_link = ws_initial_filter["self_link"]
self.assertContentEqual(
[initial_filter_link], bug_filter_links())
# A new filter appears in the bug_filters collection.
- ws_subscription_filter1 = self.ws_subscription.newBugFilter()
+ response = self.webservice.named_post(
+ self.subscription_url, "newBugFilter")
+ self.assertEqual(201, response.status)
+ ws_subscription_filter1_link = response.getHeader("Location")
self.assertContentEqual(
- [ws_subscription_filter1.self_link, initial_filter_link],
+ [ws_subscription_filter1_link, initial_filter_link],
bug_filter_links())
# A second new filter also appears in the bug_filters collection.
- ws_subscription_filter2 = self.ws_subscription.newBugFilter()
+ response = self.webservice.named_post(
+ self.subscription_url, "newBugFilter")
+ self.assertEqual(201, response.status)
+ ws_subscription_filter2_link = response.getHeader("Location")
self.assertContentEqual(
- [ws_subscription_filter1.self_link,
- ws_subscription_filter2.self_link,
+ [ws_subscription_filter1_link,
+ ws_subscription_filter2_link,
initial_filter_link],
bug_filter_links())
diff --git a/lib/lp/bugs/model/tests/test_bugtask.py b/lib/lp/bugs/model/tests/test_bugtask.py
index c2874ba..7466f7e 100644
--- a/lib/lp/bugs/model/tests/test_bugtask.py
+++ b/lib/lp/bugs/model/tests/test_bugtask.py
@@ -10,7 +10,6 @@ import subprocess
import unittest
from lazr.lifecycle.snapshot import Snapshot
-from lazr.restfulclient.errors import Unauthorized
from storm.store import Store
from testtools.matchers import Equals
from testtools.testcase import ExpectedException
@@ -86,12 +85,16 @@ from lp.services.log.logger import DevNullLogger
from lp.services.propertycache import get_property_cache
from lp.services.searchbuilder import any
from lp.services.webapp.authorization import check_permission
-from lp.services.webapp.interfaces import ILaunchBag
+from lp.services.webapp.interfaces import (
+ ILaunchBag,
+ OAuthPermission,
+ )
from lp.services.webapp.snapshot import notify_modified
from lp.soyuz.interfaces.archive import ArchivePurpose
from lp.testing import (
admin_logged_in,
ANONYMOUS,
+ api_url,
EventRecorder,
feature_flags,
login,
@@ -103,15 +106,14 @@ from lp.testing import (
StormStatementRecorder,
TestCase,
TestCaseWithFactory,
- ws_object,
)
from lp.testing.fakemethod import FakeMethod
from lp.testing.layers import (
- AppServerLayer,
CeleryJobLayer,
DatabaseFunctionalLayer,
)
from lp.testing.matchers import HasQueryCount
+from lp.testing.pages import webservice_for_person
BugData = namedtuple("BugData", ['owner', 'distro', 'distro_release',
@@ -2953,29 +2955,32 @@ class TestValidateNewTarget(TestCaseWithFactory, ValidateTargetMixin):
class TestWebservice(TestCaseWithFactory):
"""Tests for the webservice."""
- layer = AppServerLayer
+ layer = DatabaseFunctionalLayer
def test_delete_bugtask(self):
"""Test that a bugtask can be deleted."""
owner = self.factory.makePerson()
some_person = self.factory.makePerson()
- db_bug = self.factory.makeBug()
- db_bugtask = self.factory.makeBugTask(bug=db_bug, owner=owner)
- transaction.commit()
- logout()
+ bug = self.factory.makeBug()
+ bugtask = self.factory.makeBugTask(bug=bug, owner=owner)
+ bugtask_url = api_url(bugtask)
# It will fail for an unauthorised user.
- launchpad = self.factory.makeLaunchpadService(some_person)
- bugtask = ws_object(launchpad, db_bugtask)
- self.assertRaises(Unauthorized, bugtask.lp_delete)
+ webservice = webservice_for_person(
+ some_person, permission=OAuthPermission.WRITE_PUBLIC,
+ default_api_version="devel")
+ response = webservice.delete(bugtask_url)
+ self.assertEqual(401, response.status)
+
+ webservice = webservice_for_person(
+ owner, permission=OAuthPermission.WRITE_PUBLIC,
+ default_api_version="devel")
+ response = webservice.delete(bugtask_url)
+ self.assertEqual(200, response.status)
- launchpad = self.factory.makeLaunchpadService(owner)
- bugtask = ws_object(launchpad, db_bugtask)
- bugtask.lp_delete()
- transaction.commit()
# Check the delete really worked.
- with person_logged_in(removeSecurityProxy(db_bug).owner):
- self.assertEqual([db_bug.default_bugtask], db_bug.bugtasks)
+ with person_logged_in(removeSecurityProxy(bug).owner):
+ self.assertEqual([bug.default_bugtask], bug.bugtasks)
class TestBugTaskUserHasBugSupervisorPrivileges(TestCaseWithFactory):
diff --git a/lib/lp/bugs/tests/test_bug_messages_webservice.py b/lib/lp/bugs/tests/test_bug_messages_webservice.py
index feec1a7..5faae0e 100644
--- a/lib/lp/bugs/tests/test_bug_messages_webservice.py
+++ b/lib/lp/bugs/tests/test_bug_messages_webservice.py
@@ -1,4 +1,4 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
+# Copyright 2011-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Webservice unit tests related to Launchpad Bug messages."""
@@ -24,36 +24,43 @@ from lp.testing import (
logout,
person_logged_in,
TestCaseWithFactory,
- WebServiceTestCase,
)
from lp.testing.layers import (
DatabaseFunctionalLayer,
LaunchpadFunctionalLayer,
)
-from lp.testing.pages import LaunchpadWebServiceCaller
+from lp.testing.pages import (
+ LaunchpadWebServiceCaller,
+ webservice_for_person,
+ )
-class TestMessageTraversal(WebServiceTestCase):
+class TestMessageTraversal(TestCaseWithFactory):
"""Tests safe traversal of bugs.
See bug 607438."""
+ layer = LaunchpadFunctionalLayer
+
def test_message_with_attachments(self):
- bugowner = self.factory.makePerson()
- bug = self.factory.makeBug(owner=bugowner)
+ bug = self.factory.makeBug()
# Traversal over bug messages attachments has no errors.
expected_messages = []
- with person_logged_in(bugowner):
+ with person_logged_in(bug.owner):
for i in range(3):
att = self.factory.makeBugAttachment(bug)
expected_messages.append(att.message.subject)
-
- lp_user = self.factory.makePerson()
- lp_bug = self.wsObject(bug, lp_user)
-
- attachments = lp_bug.attachments
- messages = [a.message.subject for a in attachments
- if a.message is not None]
+ bug_url = api_url(bug)
+
+ webservice = webservice_for_person(self.factory.makePerson())
+ ws_bug = self.getWebserviceJSON(webservice, bug_url)
+ ws_bug_attachments = self.getWebserviceJSON(
+ webservice, ws_bug['attachments_collection_link'])
+ messages = [
+ self.getWebserviceJSON(
+ webservice, attachment['message_link'])['subject']
+ for attachment in ws_bug_attachments['entries']
+ if attachment['message_link'] is not None]
self.assertContentEqual(
messages,
expected_messages)
@@ -67,15 +74,21 @@ class TestMessageTraversal(WebServiceTestCase):
message_2 = self.factory.makeMessage()
message_2.parent = message_1
bug = self.factory.makeBug()
- bug.linkMessage(message_2)
+ with person_logged_in(bug.owner):
+ bug.linkMessage(message_2)
+ bug_url = api_url(bug)
+ message_2_url = api_url(message_2)
user = self.factory.makePerson()
- lp_bug = self.wsObject(bug, user)
- for lp_message in lp_bug.messages:
+ webservice = webservice_for_person(user)
+ ws_bug = self.getWebserviceJSON(webservice, bug_url)
+ ws_bug_messages = self.getWebserviceJSON(
+ webservice, ws_bug['messages_collection_link'])
+ for ws_message in ws_bug_messages['entries']:
# An IIndexedMessage's representation.
- self.assertIs(None, lp_message.parent)
+ self.assertIsNone(ws_message['parent_link'])
# An IMessage's representation.
- lp_message = self.wsObject(message_2, user)
- self.assertIs(None, lp_message.parent)
+ ws_message = self.getWebserviceJSON(webservice, message_2_url)
+ self.assertIsNone(ws_message['parent_link'])
class TestBugMessage(TestCaseWithFactory):
diff --git a/lib/lp/testing/__init__.py b/lib/lp/testing/__init__.py
index 6a0d9b2..747930d 100644
--- a/lib/lp/testing/__init__.py
+++ b/lib/lp/testing/__init__.py
@@ -827,6 +827,12 @@ class TestCase(testtools.TestCase, fixtures.TestWithFixtures):
"\n\n".join(str(n) for n in notifications)))
return notifications
+ def getWebserviceJSON(self, webservice, url):
+ """Get the JSON representation of a webservice object given its URL."""
+ response = webservice.get(url)
+ self.assertEqual(200, response.status)
+ return response.jsonBody()
+
class TestCaseWithFactory(TestCase):