launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #19126
Re: [Merge] lp:~cjwatson/launchpad/snap-webservice into lp:launchpad
Review: Approve code
Diff comments:
>
> === added file 'lib/lp/snappy/interfaces/webservice.py'
> --- lib/lp/snappy/interfaces/webservice.py 1970-01-01 00:00:00 +0000
> +++ lib/lp/snappy/interfaces/webservice.py 2015-07-30 15:20:46 +0000
> @@ -0,0 +1,28 @@
> +# Copyright 2015 Canonical Ltd. This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""All the interfaces that are exposed through the webservice.
> +
> +There is a declaration in ZCML somewhere that looks like:
> + <webservice:register module="lp.snappy.interfaces.webservice" />
> +
> +which tells `lazr.restful` that it should look for webservice exports here.
> +"""
> +
> +__all__ = [
> + 'ISnap',
> + 'ISnapBuild',
> + 'ISnapSet',
> + ]
> +
> +# XXX: JonathanLange 2010-11-09 bug=673083: Legacy work-around for circular
> +# import bugs. Break this up into a per-package thing.
We should indeed not further perpetuate the great horror of _schema_circular_imports. Can you move the snap-specific patches into this file directly?
> +from lp import _schema_circular_imports
> +from lp.snappy.interfaces.snap import (
> + ISnap,
> + ISnapSet,
> + )
> +from lp.snappy.interfaces.snapbuild import ISnapBuild
> +
> +
> +_schema_circular_imports
>
> === modified file 'lib/lp/snappy/tests/test_snapbuild.py'
> --- lib/lp/snappy/tests/test_snapbuild.py 2015-07-30 15:20:46 +0000
> +++ lib/lp/snappy/tests/test_snapbuild.py 2015-07-30 15:20:46 +0000
> @@ -224,3 +248,179 @@
> def test_getByBuildFarmJobs_works_empty(self):
> self.assertContentEqual(
> [], getUtility(ISnapBuildSet).getByBuildFarmJobs([]))
> +
> +
> +class NonRedirectingMechanizeBrowser(PublisherMechanizeBrowser):
> + """A `mechanize.Browser` that does not handle redirects."""
> +
> + default_features = [
> + feature for feature in PublisherMechanizeBrowser.default_features
> + if feature != "_redirect"]
PackageUpload, SourcePackageRecipeBuild, LiveFSBuild and now SnapBuild all have something like this. Perhaps put it in lp.testing?
> +
> +
> +class TestSnapBuildWebservice(TestCaseWithFactory):
> +
> + layer = LaunchpadFunctionalLayer
> +
> + def setUp(self):
> + super(TestSnapBuildWebservice, self).setUp()
> + self.useFixture(FeatureFixture({SNAP_FEATURE_FLAG: u"on"}))
> + self.person = self.factory.makePerson()
> + self.webservice = webservice_for_person(
> + self.person, permission=OAuthPermission.WRITE_PRIVATE)
> + self.webservice.default_api_version = "devel"
> + login(ANONYMOUS)
> +
> + def getURL(self, obj):
> + return self.webservice.getAbsoluteUrl(api_url(obj))
> +
> + def test_properties(self):
> + # The basic properties of a SnapBuild are sensible.
> + db_build = self.factory.makeSnapBuild(
> + requester=self.person,
> + date_created=datetime(2014, 04, 25, 10, 38, 0, tzinfo=pytz.UTC))
> + build_url = api_url(db_build)
> + logout()
> + build = self.webservice.get(build_url).jsonBody()
> + with person_logged_in(self.person):
> + self.assertEqual(self.getURL(self.person), build["requester_link"])
> + self.assertEqual(self.getURL(db_build.snap), build["snap_link"])
> + self.assertEqual(
> + self.getURL(db_build.archive), build["archive_link"])
> + self.assertEqual(
> + self.getURL(db_build.distro_arch_series),
> + build["distro_arch_series_link"])
> + self.assertEqual("Release", build["pocket"])
> + self.assertIsNone(build["score"])
> + self.assertFalse(build["can_be_rescored"])
> + self.assertFalse(build["can_be_cancelled"])
> +
> + def test_public(self):
> + # A SnapBuild with a public Snap and archive is itself public.
> + db_build = self.factory.makeSnapBuild()
> + build_url = api_url(db_build)
> + unpriv_webservice = webservice_for_person(
> + self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC)
> + unpriv_webservice.default_api_version = "devel"
> + logout()
> + self.assertEqual(200, self.webservice.get(build_url).status)
> + self.assertEqual(200, unpriv_webservice.get(build_url).status)
> +
> + def test_private_snap(self):
> + # A SnapBuild with a private Snap is private.
> + db_team = self.factory.makeTeam(
> + owner=self.person, visibility=PersonVisibility.PRIVATE)
> + with person_logged_in(self.person):
> + db_build = self.factory.makeSnapBuild(
> + requester=self.person, owner=db_team)
> + build_url = api_url(db_build)
> + unpriv_webservice = webservice_for_person(
> + self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC)
> + unpriv_webservice.default_api_version = "devel"
> + logout()
> + self.assertEqual(200, self.webservice.get(build_url).status)
> + # 404 since we aren't allowed to know that the private team exists.
> + self.assertEqual(404, unpriv_webservice.get(build_url).status)
> +
> + def test_private_archive(self):
> + # A SnapBuild with a private archive is private.
> + db_archive = self.factory.makeArchive(owner=self.person, private=True)
> + with person_logged_in(self.person):
> + db_build = self.factory.makeSnapBuild(archive=db_archive)
> + build_url = api_url(db_build)
> + unpriv_webservice = webservice_for_person(
> + self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC)
> + unpriv_webservice.default_api_version = "devel"
> + logout()
> + self.assertEqual(200, self.webservice.get(build_url).status)
> + self.assertEqual(401, unpriv_webservice.get(build_url).status)
> +
> + def test_cancel(self):
> + # The owner of a build can cancel it.
> + db_build = self.factory.makeSnapBuild(requester=self.person)
> + db_build.queueBuild()
> + build_url = api_url(db_build)
> + unpriv_webservice = webservice_for_person(
> + self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC)
> + unpriv_webservice.default_api_version = "devel"
> + logout()
> + build = self.webservice.get(build_url).jsonBody()
> + self.assertTrue(build["can_be_cancelled"])
> + response = unpriv_webservice.named_post(build["self_link"], "cancel")
> + self.assertEqual(401, response.status)
> + response = self.webservice.named_post(build["self_link"], "cancel")
> + self.assertEqual(200, response.status)
> + build = self.webservice.get(build_url).jsonBody()
> + self.assertFalse(build["can_be_cancelled"])
> + with person_logged_in(self.person):
> + self.assertEqual(BuildStatus.CANCELLED, db_build.status)
> +
> + def test_rescore(self):
> + # Buildd administrators can rescore builds.
> + db_build = self.factory.makeSnapBuild(requester=self.person)
> + db_build.queueBuild()
> + build_url = api_url(db_build)
> + buildd_admin = self.factory.makePerson(
> + member_of=[getUtility(ILaunchpadCelebrities).buildd_admin])
> + buildd_admin_webservice = webservice_for_person(
> + buildd_admin, permission=OAuthPermission.WRITE_PUBLIC)
> + buildd_admin_webservice.default_api_version = "devel"
> + logout()
> + build = self.webservice.get(build_url).jsonBody()
> + self.assertEqual(2505, build["score"])
> + self.assertTrue(build["can_be_rescored"])
> + response = self.webservice.named_post(
> + build["self_link"], "rescore", score=5000)
> + self.assertEqual(401, response.status)
> + response = buildd_admin_webservice.named_post(
> + build["self_link"], "rescore", score=5000)
> + self.assertEqual(200, response.status)
> + build = self.webservice.get(build_url).jsonBody()
> + self.assertEqual(5000, build["score"])
> +
> + def makeNonRedirectingBrowser(self, person):
> + # The test browser can only work with the appserver, not the
> + # librarian, so follow one layer of redirection through the
> + # appserver and then ask the librarian for the real file.
> + browser = Browser(mech_browser=NonRedirectingMechanizeBrowser())
> + browser.handleErrors = False
> + with person_logged_in(person):
> + browser.addHeader(
> + "Authorization", "Basic %s:test" % person.preferredemail.email)
> + return browser
> +
> + def assertCanOpenRedirectedUrl(self, browser, url):
> + redirection = self.assertRaises(HTTPError, browser.open, url)
> + self.assertEqual(303, redirection.code)
> + urlopen(redirection.hdrs["Location"]).close()
> +
> + def test_logs(self):
> + # API clients can fetch the build and upload logs.
> + db_build = self.factory.makeSnapBuild(requester=self.person)
> + db_build.setLog(self.factory.makeLibraryFileAlias("buildlog.txt.gz"))
> + db_build.storeUploadLog("uploaded")
> + build_url = api_url(db_build)
> + logout()
> + build = self.webservice.get(build_url).jsonBody()
> + browser = self.makeNonRedirectingBrowser(self.person)
> + self.assertIsNotNone(build["build_log_url"])
> + self.assertCanOpenRedirectedUrl(browser, build["build_log_url"])
> + self.assertIsNotNone(build["upload_log_url"])
> + self.assertCanOpenRedirectedUrl(browser, build["upload_log_url"])
> +
> + def test_getFileUrls(self):
> + # API clients can fetch files attached to builds.
> + db_build = self.factory.makeSnapBuild(requester=self.person)
> + db_files = [
> + self.factory.makeSnapFile(snapbuild=db_build) for i in range(2)]
> + build_url = api_url(db_build)
> + file_urls = [
> + ProxiedLibraryFileAlias(file.libraryfile, db_build).http_url
> + for file in db_files]
> + logout()
> + response = self.webservice.named_get(build_url, "getFileUrls")
> + self.assertEqual(200, response.status)
> + self.assertContentEqual(file_urls, response.jsonBody())
> + browser = self.makeNonRedirectingBrowser(self.person)
> + for file_url in file_urls:
> + self.assertCanOpenRedirectedUrl(browser, file_url)
--
https://code.launchpad.net/~cjwatson/launchpad/snap-webservice/+merge/265700
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.
References