class TestFilesystem(TestCaseWithTransport): # XXX: JonathanLange 2008-10-07 bug=267013: Many of these tests duplicate # tests in test_branchfs and test_transport. We should review the tests # and remove the ones that aren't needed. def setUp(self): super(TestFilesystem, self).setUp() self.disable_directory_isolation() frontend = InMemoryFrontend() self.factory = frontend.getLaunchpadObjectFactory() endpoint = XMLRPCWrapper(frontend.getCodehostingEndpoint()) self.requester = self.factory.makePerson() self._server = LaunchpadServer( endpoint, self.requester.id, MemoryTransport()) self._server.start_server() self.addCleanup(self._server.stop_server) def getTransport(self, relpath=None): return get_transport(self._server.get_url()).clone(relpath) def test_remove_branch_directory(self): # Make some directories under ~testuser/+junk (i.e. create some empty # branches) transport = self.getTransport('~%s/+junk' % self.requester.name) transport.mkdir('foo') transport.mkdir('bar') self.assertTrue(stat.S_ISDIR(transport.stat('foo').st_mode)) self.assertTrue(stat.S_ISDIR(transport.stat('bar').st_mode)) # Try to remove a branch directory, which is not allowed. self.assertRaises( errors.PermissionDenied, transport.rmdir, 'foo') # The 'foo' directory is still listed. self.assertTrue(transport.has('bar')) self.assertTrue(transport.has('foo')) def test_make_invalid_user_directory(self): # The top-level directory must always be of the form '~user'. However, # sometimes a transport will ask to look at files that aren't of that # form. In that case, the transport is denied permission. transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, 'apple') def test_make_valid_user_directory(self): # Making a top-level directory is not supported by the Launchpad # transport. transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~apple') def test_make_existing_user_directory(self): # Making a user directory raises an error. We don't really care what # the error is, but it should be one of FileExists, # TransportNotPossible or NoSuchFile transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~%s' % self.requester.name) def test_mkdir_not_team_member_error(self): # You can't make a branch under the directory of a team that you don't # belong to. team = self.factory.makeTeam(self.factory.makePerson()) product = self.factory.makeProduct() transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~%s/%s/new-branch' % (team.name, product.name)) def test_make_team_branch_directory(self): # You can make a branch directory under a team directory that you are # a member of (so long as it's a real product). team = self.factory.makeTeam(self.requester) product = self.factory.makeProduct() transport = self.getTransport() transport.mkdir('~%s/%s/shiny-new-thing' % (team.name, product.name)) self.assertTrue( transport.has( '~%s/%s/shiny-new-thing' % (team.name, product.name))) def test_make_product_directory_for_nonexistent_product(self): # Making a branch directory for a non-existent product is not allowed. # Products must first be registered in Launchpad. transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~%s/no-such-product/new-branch' % self.requester.name) def test_make_branch_directory(self): # We allow users to create new branches by pushing them beneath an # existing product directory. product = self.factory.makeProduct() transport = self.getTransport() branch_path = '~%s/%s/banana' % (self.requester.name, product.name) transport.mkdir(branch_path) self.assertTrue(transport.has(branch_path)) def test_make_junk_branch(self): # Users can make branches beneath their '+junk' folder. transport = self.getTransport() branch_path = '~%s/+junk/banana' % self.requester.name transport.mkdir(branch_path) self.assertTrue(transport.has(branch_path)) def test_get_stacking_policy(self): # A stacking policy control file is served underneath product # directories for products that have a default stacked-on branch. product = self.factory.makeProduct() self.factory.enableDefaultStackingForProduct(product) transport = self.getTransport() control_file = transport.get_bytes( '~%s/%s/.bzr/control.conf' % (self.requester.name, product.name)) stacked_on = IBranchTarget(product).default_stacked_on_branch self.assertEqual( 'default_stack_on = %s' % branch_id_alias(stacked_on), control_file.strip()) def test_can_open_product_control_dir(self): # The stacking policy lives in a bzrdir in the product directory. # Bazaar needs to be able to open this bzrdir. product = self.factory.makeProduct() self.factory.enableDefaultStackingForProduct(product) transport = self.getTransport().clone( '~%s/%s' % (self.requester.name, product.name)) found_bzrdir = BzrDir.open_from_transport(transport) # We really just want to test that the above line doesn't raise an # exception. However, we'll also check that we get the bzrdir that we # expected. expected_url = transport.clone('.bzr').base self.assertEqual(expected_url, found_bzrdir.transport.base) def test_directory_inside_branch(self): # We allow users to create new branches by pushing them beneath an # existing product directory. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/.bzr' % branch_path) self.assertTrue(transport.has(branch_path)) self.assertTrue(transport.has('%s/.bzr' % branch_path)) def test_bzr_backup_directory_inside_branch(self): # Bazaar sometimes needs to create .bzr.backup directories directly # underneath the branch directory. Thus, we allow the creation of # .bzr.backup directories. The .bzr.backup directory is a deprecated # name. Now Bazaar uses 'backup.bzr'. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/.bzr.backup' % branch_path) self.assertTrue(transport.has(branch_path)) self.assertTrue(transport.has('%s/.bzr.backup' % branch_path)) def test_backup_bzr_directory_inside_branch(self): # Bazaar sometimes needs to create backup.bzr directories directly # underneath the branch directory. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/backup.bzr' % branch_path) self.assertTrue(transport.has(branch_path)) self.assertTrue(transport.has('%s/backup.bzr' % branch_path)) def test_non_bzr_directory_inside_branch(self): # Users can only create Bazaar control directories (e.g. '.bzr') # inside a branch. Other directories are strictly forbidden. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) self.assertRaises( errors.PermissionDenied, transport.mkdir, '%s/not-a-bzr-dir' % branch_path) def test_non_bzr_file_inside_branch(self): # Users can only create Bazaar control directories (e.g. '.bzr') # inside a branch. Files are not allowed. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) self.assertRaises( errors.PermissionDenied, transport.put_bytes, '%s/README' % branch_path, 'Hello!') def test_rename_to_non_bzr_directory_fails(self): # Users cannot create an allowed directory (e.g. '.bzr' or # 'backup.bzr') and then rename it to something that's not allowed # (e.g. 'republic'). product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/.bzr' % branch_path) self.assertRaises( errors.PermissionDenied, transport.rename, '%s/.bzr' % branch_path, '%s/not-a-branch-dir' % branch_path) def test_make_directory_without_prefix(self): # Because the user and product directories don't exist on the # filesystem, we can create a branch directory for a product even if # there are no existing branches for that product. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) self.assertTrue(transport.has(branch_path)) def _getBzrDirTransport(self): """Make a .bzr directory in a branch and return a transport for it. We use this to test filesystem behaviour beneath the .bzr directory of a branch, which generally has fewer constraints and exercises different code paths. """ product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport = transport.clone(branch_path) transport.mkdir('.bzr') return transport.clone('.bzr') def test_rename_directory_to_existing_directory_fails(self): # 'rename dir1 dir2' should fail if 'dir2' exists. Unfortunately, it # will only fail if they both contain files/directories. transport = self._getBzrDirTransport() transport.mkdir('dir1') transport.mkdir('dir1/foo') transport.mkdir('dir2') transport.mkdir('dir2/bar') self.assertRaises(errors.FileExists, transport.rename, 'dir1', 'dir2') def test_rename_directory_succeeds(self): # 'rename dir1 dir2' succeeds if 'dir2' doesn't exist. transport = self._getBzrDirTransport() transport.mkdir('dir1') transport.mkdir('dir1/foo') transport.rename('dir1', 'dir2') self.assertEqual(['dir2'], transport.list_dir('.')) def test_make_directory_twice(self): # The transport raises a `FileExists` error if we try to make a # directory that already exists. transport = self._getBzrDirTransport() transport.mkdir('dir1') self.assertRaises(errors.FileExists, transport.mkdir, 'dir1') def test_url_escaping(self): # Transports accept and return escaped URL segments. The literal path # we use should be preserved, even if it can be unescaped itself. transport = self._getBzrDirTransport() # The bug we are checking only occurs if # unescape(path).encode('utf-8') != path. path = '%41%42%43' escaped_path = escape(path) content = 'content' transport.put_bytes(escaped_path, content) # We can use the escaped path to reach the file. self.assertEqual(content, transport.get_bytes(escaped_path)) # We can also use the value that list_dir returns, which may be # different from our original escaped path. Note that in this case, # returned_path is equivalent but not equal to escaped_path. [returned_path] = list(transport.list_dir('.')) self.assertEqual(content, transport.get_bytes(returned_path))
class TestFilesystem(TestCaseWithTransport): # XXX: JonathanLange 2008-10-07 bug=267013: Many of these tests duplicate # tests in test_branchfs and test_transport. We should review the tests # and remove the ones that aren't needed. def setUp(self): super(TestFilesystem, self).setUp() self.disable_directory_isolation() frontend = InMemoryFrontend() self.factory = frontend.getLaunchpadObjectFactory() endpoint = XMLRPCWrapper(frontend.getCodehostingEndpoint()) self.requester = self.factory.makePerson() self._server = LaunchpadServer( endpoint, self.requester.id, MemoryTransport()) self._server.start_server() self.addCleanup(self._server.stop_server) def getTransport(self, relpath=None): return get_transport(self._server.get_url()).clone(relpath) def test_remove_branch_directory(self): # Make some directories under ~testuser/+junk (i.e. create some empty # branches) transport = self.getTransport('~%s/+junk' % self.requester.name) transport.mkdir('foo') transport.mkdir('bar') self.failUnless(stat.S_ISDIR(transport.stat('foo').st_mode)) self.failUnless(stat.S_ISDIR(transport.stat('bar').st_mode)) # Try to remove a branch directory, which is not allowed. self.assertRaises( errors.PermissionDenied, transport.rmdir, 'foo') # The 'foo' directory is still listed. self.assertTrue(transport.has('bar')) self.assertTrue(transport.has('foo')) def test_make_invalid_user_directory(self): # The top-level directory must always be of the form '~user'. However, # sometimes a transport will ask to look at files that aren't of that # form. In that case, the transport is denied permission. transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, 'apple') def test_make_valid_user_directory(self): # Making a top-level directory is not supported by the Launchpad # transport. transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~apple') def test_make_existing_user_directory(self): # Making a user directory raises an error. We don't really care what # the error is, but it should be one of FileExists, # TransportNotPossible or NoSuchFile transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~%s' % self.requester.name) def test_mkdir_not_team_member_error(self): # You can't make a branch under the directory of a team that you don't # belong to. team = self.factory.makeTeam(self.factory.makePerson()) product = self.factory.makeProduct() transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~%s/%s/new-branch' % (team.name, product.name)) def test_make_team_branch_directory(self): # You can make a branch directory under a team directory that you are # a member of (so long as it's a real product). team = self.factory.makeTeam(self.requester) product = self.factory.makeProduct() transport = self.getTransport() transport.mkdir('~%s/%s/shiny-new-thing' % (team.name, product.name)) self.assertTrue( transport.has( '~%s/%s/shiny-new-thing' % (team.name, product.name))) def test_make_product_directory_for_nonexistent_product(self): # Making a branch directory for a non-existent product is not allowed. # Products must first be registered in Launchpad. transport = self.getTransport() self.assertRaises( errors.PermissionDenied, transport.mkdir, '~%s/no-such-product/new-branch' % self.requester.name) def test_make_branch_directory(self): # We allow users to create new branches by pushing them beneath an # existing product directory. product = self.factory.makeProduct() transport = self.getTransport() branch_path = '~%s/%s/banana' % (self.requester.name, product.name) transport.mkdir(branch_path) self.assertTrue(transport.has(branch_path)) def test_make_junk_branch(self): # Users can make branches beneath their '+junk' folder. transport = self.getTransport() branch_path = '~%s/+junk/banana' % self.requester.name transport.mkdir(branch_path) self.assertTrue(transport.has(branch_path)) def test_get_stacking_policy(self): # A stacking policy control file is served underneath product # directories for products that have a default stacked-on branch. product = self.factory.makeProduct() self.factory.enableDefaultStackingForProduct(product) transport = self.getTransport() control_file = transport.get_bytes( '~%s/%s/.bzr/control.conf' % (self.requester.name, product.name)) stacked_on = IBranchTarget(product).default_stacked_on_branch self.assertEqual( 'default_stack_on = %s' % branch_id_alias(stacked_on), control_file.strip()) def test_can_open_product_control_dir(self): # The stacking policy lives in a bzrdir in the product directory. # Bazaar needs to be able to open this bzrdir. product = self.factory.makeProduct() self.factory.enableDefaultStackingForProduct(product) transport = self.getTransport().clone( '~%s/%s' % (self.requester.name, product.name)) found_bzrdir = BzrDir.open_from_transport(transport) # We really just want to test that the above line doesn't raise an # exception. However, we'll also check that we get the bzrdir that we # expected. expected_url = transport.clone('.bzr').base self.assertEqual(expected_url, found_bzrdir.transport.base) def test_directory_inside_branch(self): # We allow users to create new branches by pushing them beneath an # existing product directory. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/.bzr' % branch_path) self.assertTrue(transport.has(branch_path)) self.assertTrue(transport.has('%s/.bzr' % branch_path)) def test_bzr_backup_directory_inside_branch(self): # Bazaar sometimes needs to create .bzr.backup directories directly # underneath the branch directory. Thus, we allow the creation of # .bzr.backup directories. The .bzr.backup directory is a deprecated # name. Now Bazaar uses 'backup.bzr'. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/.bzr.backup' % branch_path) self.assertTrue(transport.has(branch_path)) self.assertTrue(transport.has('%s/.bzr.backup' % branch_path)) def test_backup_bzr_directory_inside_branch(self): # Bazaar sometimes needs to create backup.bzr directories directly # underneath the branch directory. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/backup.bzr' % branch_path) self.assertTrue(transport.has(branch_path)) self.assertTrue(transport.has('%s/backup.bzr' % branch_path)) def test_non_bzr_directory_inside_branch(self): # Users can only create Bazaar control directories (e.g. '.bzr') # inside a branch. Other directories are strictly forbidden. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) self.assertRaises( errors.PermissionDenied, transport.mkdir, '%s/not-a-bzr-dir' % branch_path) def test_non_bzr_file_inside_branch(self): # Users can only create Bazaar control directories (e.g. '.bzr') # inside a branch. Files are not allowed. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) self.assertRaises( errors.PermissionDenied, transport.put_bytes, '%s/README' % branch_path, 'Hello!') def test_rename_to_non_bzr_directory_fails(self): # Users cannot create an allowed directory (e.g. '.bzr' or # 'backup.bzr') and then rename it to something that's not allowed # (e.g. 'republic'). product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport.mkdir('%s/.bzr' % branch_path) self.assertRaises( errors.PermissionDenied, transport.rename, '%s/.bzr' % branch_path, '%s/not-a-branch-dir' % branch_path) def test_make_directory_without_prefix(self): # Because the user and product directories don't exist on the # filesystem, we can create a branch directory for a product even if # there are no existing branches for that product. product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) self.assertTrue(transport.has(branch_path)) def _getBzrDirTransport(self): """Make a .bzr directory in a branch and return a transport for it. We use this to test filesystem behaviour beneath the .bzr directory of a branch, which generally has fewer constraints and exercises different code paths. """ product = self.factory.makeProduct() branch_path = '~%s/%s/%s' % ( self.requester.name, product.name, self.factory.getUniqueString()) transport = self.getTransport() transport.mkdir(branch_path) transport = transport.clone(branch_path) transport.mkdir('.bzr') return transport.clone('.bzr') def test_rename_directory_to_existing_directory_fails(self): # 'rename dir1 dir2' should fail if 'dir2' exists. Unfortunately, it # will only fail if they both contain files/directories. transport = self._getBzrDirTransport() transport.mkdir('dir1') transport.mkdir('dir1/foo') transport.mkdir('dir2') transport.mkdir('dir2/bar') self.assertRaises(errors.FileExists, transport.rename, 'dir1', 'dir2') def test_rename_directory_succeeds(self): # 'rename dir1 dir2' succeeds if 'dir2' doesn't exist. transport = self._getBzrDirTransport() transport.mkdir('dir1') transport.mkdir('dir1/foo') transport.rename('dir1', 'dir2') self.assertEqual(['dir2'], transport.list_dir('.')) def test_make_directory_twice(self): # The transport raises a `FileExists` error if we try to make a # directory that already exists. transport = self._getBzrDirTransport() transport.mkdir('dir1') self.assertRaises(errors.FileExists, transport.mkdir, 'dir1') def test_url_escaping(self): # Transports accept and return escaped URL segments. The literal path # we use should be preserved, even if it can be unescaped itself. transport = self._getBzrDirTransport() # The bug we are checking only occurs if # unescape(path).encode('utf-8') != path. path = '%41%42%43' escaped_path = escape(path) content = 'content' transport.put_bytes(escaped_path, content) # We can use the escaped path to reach the file. self.assertEqual(content, transport.get_bytes(escaped_path)) # We can also use the value that list_dir returns, which may be # different from our original escaped path. Note that in this case, # returned_path is equivalent but not equal to escaped_path. [returned_path] = list(transport.list_dir('.')) self.assertEqual(content, transport.get_bytes(returned_path))