diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 85297900c3..158462d18a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,24 @@ Once those steps have been completed, changes to OpenStack should be submitted for review via the Gerrit tool, following the workflow documented at [http://wiki.openstack.org/GerritWorkflow](http://wiki.openstack.org/GerritWorkflow). -Pull requests submitted through GitHub will be ignored. +Gerrit is the review system used in the OpenStack projects. We're sorry, but +we won't be able to respond to pull requests submitted through GitHub. Bugs should be filed [on Launchpad](https://bugs.launchpad.net/swift), not in GitHub's issue tracker. + +Recommended workflow +==================== + + * Set up a [Swift All-In-One VM](http://docs.openstack.org/developer/swift/development_saio.html). + + * Make your changes. + + * Run unit tests, functional tests, probe tests + ``./.unittests`` + ``./.functests`` + ``./.probetests`` + + * Run ``tox`` (no command-line args needed) + + * ``git review`` diff --git a/swift/proxy/controllers/account.py b/swift/proxy/controllers/account.py index 2d2aa36677..476af01bd6 100644 --- a/swift/proxy/controllers/account.py +++ b/swift/proxy/controllers/account.py @@ -31,7 +31,7 @@ from swift.account.utils import account_listing_response from swift.common.request_helpers import get_listing_content_type from swift.common.utils import public from swift.common.constraints import check_metadata, MAX_ACCOUNT_NAME_LENGTH -from swift.common.http import HTTP_NOT_FOUND +from swift.common.http import HTTP_NOT_FOUND, HTTP_GONE from swift.proxy.controllers.base import Controller, clear_info_cache from swift.common.swob import HTTPBadRequest, HTTPMethodNotAllowed @@ -59,9 +59,12 @@ class AccountController(Controller): resp = self.GETorHEAD_base( req, _('Account'), self.app.account_ring, partition, req.path_info.rstrip('/')) - if resp.status_int == HTTP_NOT_FOUND and self.app.account_autocreate: - resp = account_listing_response(self.account_name, req, - get_listing_content_type(req)) + if resp.status_int == HTTP_NOT_FOUND: + if resp.headers.get('X-Account-Status', '').lower() == 'deleted': + resp.status = HTTP_GONE + elif self.app.account_autocreate: + resp = account_listing_response(self.account_name, req, + get_listing_content_type(req)) if not req.environ.get('swift_owner', False): for key in self.app.swift_owner_headers: if key in resp.headers: diff --git a/test/unit/proxy/controllers/test_account.py b/test/unit/proxy/controllers/test_account.py index 394ada73fc..c0a5d93748 100644 --- a/test/unit/proxy/controllers/test_account.py +++ b/test/unit/proxy/controllers/test_account.py @@ -19,6 +19,7 @@ import unittest from swift.common.swob import Request from swift.proxy import server as proxy_server from swift.proxy.controllers.base import headers_to_account_info +from swift.common.constraints import MAX_ACCOUNT_NAME_LENGTH as MAX_ANAME_LEN from test.unit import fake_http_connect, FakeRing, FakeMemcache @@ -32,7 +33,7 @@ class TestAccountController(unittest.TestCase): def test_account_info_in_response_env(self): controller = proxy_server.AccountController(self.app, 'AUTH_bob') with mock.patch('swift.proxy.controllers.base.http_connect', - fake_http_connect(200, 200, body='')): + fake_http_connect(200, body='')): req = Request.blank('/AUTH_bob', {'PATH_INFO': '/AUTH_bob'}) resp = controller.HEAD(req) self.assertEqual(2, resp.status_int // 100) @@ -48,7 +49,7 @@ class TestAccountController(unittest.TestCase): req = Request.blank('/a') with mock.patch('swift.proxy.controllers.base.http_connect', - fake_http_connect(200, 200, headers=owner_headers)): + fake_http_connect(200, headers=owner_headers)): resp = controller.HEAD(req) self.assertEquals(2, resp.status_int // 100) for key in owner_headers: @@ -56,12 +57,44 @@ class TestAccountController(unittest.TestCase): req = Request.blank('/a', environ={'swift_owner': True}) with mock.patch('swift.proxy.controllers.base.http_connect', - fake_http_connect(200, 200, headers=owner_headers)): + fake_http_connect(200, headers=owner_headers)): resp = controller.HEAD(req) self.assertEquals(2, resp.status_int // 100) for key in owner_headers: self.assertTrue(key in resp.headers) + def test_get_deleted_account(self): + resp_headers = { + 'x-account-status': 'deleted', + } + controller = proxy_server.AccountController(self.app, 'a') + + req = Request.blank('/a') + with mock.patch('swift.proxy.controllers.base.http_connect', + fake_http_connect(404, headers=resp_headers)): + resp = controller.HEAD(req) + self.assertEquals(410, resp.status_int) + + def test_long_acct_names(self): + long_acct_name = '%sLongAccountName' % ('Very' * (MAX_ANAME_LEN // 4)) + controller = proxy_server.AccountController(self.app, long_acct_name) + + req = Request.blank('/%s' % long_acct_name) + with mock.patch('swift.proxy.controllers.base.http_connect', + fake_http_connect(200)): + resp = controller.HEAD(req) + self.assertEquals(400, resp.status_int) + + with mock.patch('swift.proxy.controllers.base.http_connect', + fake_http_connect(200)): + resp = controller.GET(req) + self.assertEquals(400, resp.status_int) + + with mock.patch('swift.proxy.controllers.base.http_connect', + fake_http_connect(200)): + resp = controller.POST(req) + self.assertEquals(400, resp.status_int) + if __name__ == '__main__': unittest.main()