Back to index

obnam  1.1
repo_tests.py
Go to the documentation of this file.
00001 # Copyright (C) 2010-2011  Lars Wirzenius
00002 #
00003 # This program is free software: you can redistribute it and/or modify
00004 # it under the terms of the GNU General Public License as published by
00005 # the Free Software Foundation, either version 3 of the License, or
00006 # (at your option) any later version.
00007 #
00008 # This program is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 # GNU General Public License for more details.
00012 #
00013 # You should have received a copy of the GNU General Public License
00014 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015 
00016 
00017 import hashlib
00018 import os
00019 import shutil
00020 import stat
00021 import tempfile
00022 import time
00023 import unittest
00024 
00025 import obnamlib
00026 
00027 
00028 class RepositoryRootNodeTests(unittest.TestCase):
00029 
00030     def setUp(self):
00031         self.tempdir = tempfile.mkdtemp()
00032 
00033         self.fs = obnamlib.LocalFS(self.tempdir)
00034         self.repo = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00035                                         obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00036                                         obnamlib.DEFAULT_LRU_SIZE, None,
00037                                         obnamlib.IDPATH_DEPTH,
00038                                         obnamlib.IDPATH_BITS,
00039                                         obnamlib.IDPATH_SKIP,
00040                                         time.time, 0, '')
00041         
00042         self.otherfs = obnamlib.LocalFS(self.tempdir)
00043         self.other = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00044                                          obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00045                                          obnamlib.DEFAULT_LRU_SIZE, None,
00046                                         obnamlib.IDPATH_DEPTH,
00047                                         obnamlib.IDPATH_BITS,
00048                                         obnamlib.IDPATH_SKIP,
00049                                         time.time, 0, '')
00050 
00051     def tearDown(self):
00052         shutil.rmtree(self.tempdir)
00053 
00054     def test_has_format_version(self):
00055         self.assert_(hasattr(self.repo, 'format_version'))
00056 
00057     def test_accepts_same_format_version(self):
00058         self.assert_(self.repo.acceptable_version(self.repo.format_version))
00059 
00060     def test_does_not_accept_older_format_version(self):
00061         older_version = self.repo.format_version - 1
00062         self.assertFalse(self.repo.acceptable_version(older_version))
00063 
00064     def test_does_not_accept_newer_version(self):
00065         newer_version = self.repo.format_version + 1
00066         self.assertFalse(self.repo.acceptable_version(newer_version))
00067         
00068     def test_has_none_version_for_empty_repository(self):
00069         self.assertEqual(self.repo.get_format_version(), None)
00070         
00071     def test_creates_repository_with_format_version(self):
00072         self.repo.lock_root()
00073         self.assertEqual(self.repo.get_format_version(), 
00074                          self.repo.format_version)
00075 
00076     def test_lists_no_clients(self):
00077         self.assertEqual(self.repo.list_clients(), [])
00078 
00079     def test_has_not_got_root_node_lock(self):
00080         self.assertFalse(self.repo.got_root_lock)
00081 
00082     def test_locks_root_node(self):
00083         self.repo.lock_root()
00084         self.assert_(self.repo.got_root_lock)
00085         
00086     def test_locking_root_node_twice_fails(self):
00087         self.repo.lock_root()
00088         self.assertRaises(obnamlib.Error, self.repo.lock_root)
00089         
00090     def test_commit_releases_lock(self):
00091         self.repo.lock_root()
00092         self.repo.commit_root()
00093         self.assertFalse(self.repo.got_root_lock)
00094         
00095     def test_unlock_releases_lock(self):
00096         self.repo.lock_root()
00097         self.repo.unlock_root()
00098         self.assertFalse(self.repo.got_root_lock)
00099         
00100     def test_commit_without_lock_fails(self):
00101         self.assertRaises(obnamlib.LockFail, self.repo.commit_root)
00102         
00103     def test_unlock_root_without_lock_fails(self):
00104         self.assertRaises(obnamlib.LockFail, self.repo.unlock_root)
00105 
00106     def test_commit_when_locked_by_other_fails(self):
00107         self.other.lock_root()
00108         self.assertRaises(obnamlib.LockFail, self.repo.commit_root)
00109 
00110     def test_unlock_root_when_locked_by_other_fails(self):
00111         self.other.lock_root()
00112         self.assertRaises(obnamlib.LockFail, self.repo.unlock_root)
00113 
00114     def test_on_disk_repository_has_no_version_initially(self):
00115         self.assertEqual(self.repo.get_format_version(), None)
00116 
00117     def test_lock_root_adds_version(self):
00118         self.repo.lock_root()
00119         self.assertEqual(self.repo.get_format_version(),
00120                          self.repo.format_version)
00121 
00122     def test_lock_root_fails_if_format_is_incompatible(self):
00123         self.repo._write_format_version(0)
00124         self.assertRaises(obnamlib.BadFormat, self.repo.lock_root)
00125 
00126     def test_list_clients_fails_if_format_is_incompatible(self):
00127         self.repo._write_format_version(0)
00128         self.assertRaises(obnamlib.BadFormat, self.repo.list_clients)
00129 
00130     def test_locks_shared(self):
00131         self.repo.lock_shared()
00132         self.assertTrue(self.repo.got_shared_lock)
00133         
00134     def test_locking_shared_twice_fails(self):
00135         self.repo.lock_shared()
00136         self.assertRaises(obnamlib.Error, self.repo.lock_shared)
00137 
00138     def test_unlocks_shared(self):
00139         self.repo.lock_shared()
00140         self.repo.unlock_shared()
00141         self.assertFalse(self.repo.got_shared_lock)
00142 
00143     def test_unlock_shared_when_locked_by_other_fails(self):
00144         self.other.lock_shared()
00145         self.assertRaises(obnamlib.LockFail, self.repo.unlock_shared)
00146 
00147     def test_lock_client_fails_if_format_is_incompatible(self):
00148         self.repo._write_format_version(0)
00149         self.assertRaises(obnamlib.BadFormat, self.repo.lock_client, 'foo')
00150 
00151     def test_open_client_fails_if_format_is_incompatible(self):
00152         self.repo._write_format_version(0)
00153         self.assertRaises(obnamlib.BadFormat, self.repo.open_client, 'foo')
00154         
00155     def test_adding_client_without_root_lock_fails(self):
00156         self.assertRaises(obnamlib.LockFail, self.repo.add_client, 'foo')
00157         
00158     def test_adds_client(self):
00159         self.repo.lock_root()
00160         self.repo.add_client('foo')
00161         self.assertEqual(self.repo.list_clients(), ['foo'])
00162         
00163     def test_adds_two_clients_across_commits(self):
00164         self.repo.lock_root()
00165         self.repo.add_client('foo')
00166         self.repo.commit_root()
00167         self.repo.lock_root()
00168         self.repo.add_client('bar')
00169         self.repo.commit_root()
00170         self.assertEqual(sorted(self.repo.list_clients()), ['bar', 'foo'])
00171         
00172     def test_adds_client_that_persists_after_commit(self):
00173         self.repo.lock_root()
00174         self.repo.add_client('foo')
00175         self.repo.commit_root()
00176         s2 = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00177                                  obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00178                                  obnamlib.DEFAULT_LRU_SIZE, None,
00179                                  obnamlib.IDPATH_DEPTH,
00180                                  obnamlib.IDPATH_BITS,
00181                                  obnamlib.IDPATH_SKIP,
00182                                  time.time, 0, '')
00183         self.assertEqual(s2.list_clients(), ['foo'])
00184         
00185     def test_adding_existing_client_fails(self):
00186         self.repo.lock_root()
00187         self.repo.add_client('foo')
00188         self.assertRaises(obnamlib.Error, self.repo.add_client, 'foo')
00189         
00190     def test_removing_client_without_root_lock_fails(self):
00191         self.assertRaises(obnamlib.LockFail, self.repo.remove_client, 'foo')
00192         
00193     def test_removing_nonexistent_client_fails(self):
00194         self.repo.lock_root()
00195         self.assertRaises(obnamlib.Error, self.repo.remove_client, 'foo')
00196         
00197     def test_removing_client_works(self):
00198         self.repo.lock_root()
00199         self.repo.add_client('foo')
00200         self.repo.remove_client('foo')
00201         self.assertEqual(self.repo.list_clients(), [])
00202         
00203     def test_removing_client_persists_past_commit(self):
00204         self.repo.lock_root()
00205         self.repo.add_client('foo')
00206         self.repo.remove_client('foo')
00207         self.repo.commit_root()
00208         self.assertEqual(self.repo.list_clients(), [])
00209 
00210     def test_adding_client_without_commit_does_not_happen(self):
00211         self.repo.lock_root()
00212         self.repo.add_client('foo')
00213         self.repo.unlock_root()
00214         self.assertEqual(self.repo.list_clients(), [])
00215 
00216     def test_removing_client_without_commit_does_not_happen(self):
00217         self.repo.lock_root()
00218         self.repo.add_client('foo')
00219         self.repo.commit_root()
00220         self.repo.lock_root()
00221         self.repo.remove_client('foo')
00222         self.repo.unlock_root()
00223         self.assertEqual(self.repo.list_clients(), ['foo'])
00224 
00225     def test_removing_client_that_has_data_removes_the_data_as_well(self):
00226         self.repo.lock_root()
00227         self.repo.add_client('foo')
00228         self.repo.commit_root()
00229 
00230         self.repo.lock_client('foo')
00231         self.repo.lock_shared()
00232         self.repo.start_generation()
00233         self.repo.create('/', obnamlib.Metadata())
00234         self.repo.commit_client()
00235         self.repo.commit_shared()
00236 
00237         self.repo.lock_root()
00238         self.repo.remove_client('foo')
00239         self.repo.commit_root()
00240 
00241         self.assertEqual(self.repo.list_clients(), [])
00242         self.assertFalse(self.fs.exists('foo'))
00243 
00244 
00245 class RepositoryClientTests(unittest.TestCase):
00246 
00247     def setUp(self):
00248         self.tempdir = tempfile.mkdtemp()
00249 
00250         self.fs = obnamlib.LocalFS(self.tempdir)
00251         self.repo = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00252                                         obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00253                                         obnamlib.DEFAULT_LRU_SIZE, None,
00254                                         obnamlib.IDPATH_DEPTH,
00255                                         obnamlib.IDPATH_BITS,
00256                                         obnamlib.IDPATH_SKIP,
00257                                         time.time, 0, '')
00258         self.repo.lock_root()
00259         self.repo.add_client('client_name')
00260         self.repo.commit_root()
00261         
00262         self.otherfs = obnamlib.LocalFS(self.tempdir)
00263         self.other = obnamlib.Repository(self.otherfs, 
00264                                          obnamlib.DEFAULT_NODE_SIZE,
00265                                          obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00266                                          obnamlib.DEFAULT_LRU_SIZE, None,
00267                                          obnamlib.IDPATH_DEPTH,
00268                                          obnamlib.IDPATH_BITS,
00269                                          obnamlib.IDPATH_SKIP,
00270                                          time.time, 0, '')
00271         
00272         self.dir_meta = obnamlib.Metadata()
00273         self.dir_meta.st_mode = stat.S_IFDIR | 0777
00274 
00275     def tearDown(self):
00276         shutil.rmtree(self.tempdir)
00277 
00278     def test_has_not_got_client_lock(self):
00279         self.assertFalse(self.repo.got_client_lock)
00280 
00281     def test_locks_client(self):
00282         self.repo.lock_client('client_name')
00283         self.assert_(self.repo.got_client_lock)
00284 
00285     def test_locking_client_twice_fails(self):
00286         self.repo.lock_client('client_name')
00287         self.assertRaises(obnamlib.Error, self.repo.lock_client, 
00288                           'client_name')
00289 
00290     def test_locking_nonexistent_client_fails(self):
00291         self.assertRaises(obnamlib.LockFail, self.repo.lock_client, 'foo')
00292 
00293     def test_unlock_client_releases_lock(self):
00294         self.repo.lock_client('client_name')
00295         self.repo.unlock_client()
00296         self.assertFalse(self.repo.got_client_lock)
00297 
00298     def test_commit_client_releases_lock(self):
00299         self.repo.lock_client('client_name')
00300         self.repo.lock_shared()
00301         self.repo.commit_client()
00302         self.repo.commit_shared()
00303         self.assertFalse(self.repo.got_client_lock)
00304 
00305     def test_commit_does_not_mark_as_checkpoint_by_default(self):
00306         self.repo.lock_client('client_name')
00307         self.repo.lock_shared()
00308         self.repo.start_generation()
00309         genid = self.repo.new_generation
00310         self.repo.commit_client()
00311         self.repo.commit_shared()
00312         self.repo.open_client('client_name')
00313         self.assertFalse(self.repo.get_is_checkpoint(genid))
00314 
00315     def test_commit_marks_as_checkpoint_when_requested(self):
00316         self.repo.lock_client('client_name')
00317         self.repo.lock_shared()
00318         self.repo.start_generation()
00319         genid = self.repo.new_generation
00320         self.repo.commit_client(checkpoint=True)
00321         self.repo.commit_shared()
00322 
00323         self.repo.open_client('client_name')
00324         self.assert_(self.repo.get_is_checkpoint(genid))
00325 
00326     def test_commit_client_without_lock_fails(self):
00327         self.assertRaises(obnamlib.LockFail, self.repo.commit_client)
00328         
00329     def test_unlock_client_without_lock_fails(self):
00330         self.assertRaises(obnamlib.LockFail, self.repo.unlock_client)
00331 
00332     def test_commit_client_when_locked_by_other_fails(self):
00333         self.other.lock_client('client_name')
00334         self.assertRaises(obnamlib.LockFail, self.repo.commit_client)
00335 
00336     def test_unlock_client_when_locked_by_other_fails(self):
00337         self.other.lock_client('client_name')
00338         self.assertRaises(obnamlib.LockFail, self.repo.unlock_client)
00339 
00340     def test_opens_client_fails_if_client_does_not_exist(self):
00341         self.assertRaises(obnamlib.Error, self.repo.open_client, 'bad')
00342 
00343     def test_opens_client_even_when_locked_by_other(self):
00344         self.other.lock_client('client_name')
00345         self.repo.open_client('client_name')
00346         self.assert_(True)
00347         
00348     def test_lists_no_generations_when_readonly(self):
00349         self.repo.open_client('client_name')
00350         self.assertEqual(self.repo.list_generations(), [])
00351         
00352     def test_lists_no_generations_when_locked(self):
00353         self.repo.lock_client('client_name')
00354         self.assertEqual(self.repo.list_generations(), [])
00355         
00356     def test_listing_generations_fails_if_client_is_not_open(self):
00357         self.assertRaises(obnamlib.Error, self.repo.list_generations)
00358 
00359     def test_not_making_new_generation(self):
00360         self.assertEqual(self.repo.new_generation, None)
00361 
00362     def test_starting_new_generation_without_lock_fails(self):
00363         self.assertRaises(obnamlib.LockFail, self.repo.start_generation)
00364 
00365     def test_starting_new_generation_works(self):
00366         self.repo.lock_client('client_name')
00367         gen = self.repo.start_generation()
00368         self.assert_(self.repo.new_generation)
00369         self.assertEqual(self.repo.new_generation, gen)
00370         self.assertEqual(self.repo.list_generations(),  [gen])
00371 
00372     def test_starting_second_concurrent_new_generation_fails(self):
00373         self.repo.lock_client('client_name')
00374         self.repo.start_generation()
00375         self.assertRaises(obnamlib.Error, self.repo.start_generation)
00376 
00377     def test_second_generation_has_different_id_from_first(self):
00378         self.repo.lock_client('client_name')
00379         self.repo.lock_shared()
00380         gen = self.repo.start_generation()
00381         self.repo.commit_client()
00382         self.repo.commit_shared()
00383         self.repo.lock_client('client_name')
00384         self.assertNotEqual(gen, self.repo.start_generation())
00385 
00386     def test_new_generation_has_start_time_only(self):
00387         self.repo.lock_client('client_name')
00388         gen = self.repo.start_generation()
00389         start, end = self.repo.get_generation_times(gen)
00390         self.assertNotEqual(start, None)
00391         self.assertEqual(end, None)
00392 
00393     def test_commited_generation_has_start_and_end_times(self):
00394         self.repo.lock_client('client_name')
00395         self.repo.lock_shared()
00396         gen = self.repo.start_generation()
00397         self.repo.commit_client()
00398         self.repo.commit_shared()
00399 
00400         self.repo.open_client('client_name')
00401         start, end = self.repo.get_generation_times(gen)
00402         self.assertNotEqual(start, None)
00403         self.assertNotEqual(end, None)
00404         self.assert_(start <= end)
00405 
00406     def test_adding_generation_without_committing_does_not_add_it(self):
00407         self.repo.lock_client('client_name')
00408         self.repo.lock_shared()
00409         self.repo.start_generation()
00410         self.repo.unlock_client()
00411         self.repo.unlock_shared()
00412         self.repo.open_client('client_name')
00413         self.assertEqual(self.repo.list_generations(), [])
00414 
00415     def test_removing_generation_works(self):
00416         self.repo.lock_client('client_name')
00417         self.repo.lock_shared()
00418         gen = self.repo.start_generation()
00419         self.repo.commit_client()
00420         self.repo.commit_shared()
00421 
00422         self.repo.open_client('client_name')
00423         self.assertEqual(len(self.repo.list_generations()), 1)
00424 
00425         self.repo.lock_client('client_name')
00426         self.repo.lock_shared()
00427         self.repo.remove_generation(gen)
00428         self.repo.commit_client()
00429         self.repo.commit_shared()
00430 
00431         self.repo.open_client('client_name')
00432         self.assertEqual(self.repo.list_generations(), [])
00433 
00434     def test_removing_only_second_generation_works(self):
00435         # Create first generation. It will be empty.
00436         self.repo.lock_client('client_name')
00437         self.repo.lock_shared()
00438         gen1 = self.repo.start_generation()
00439         self.repo.commit_client()
00440         self.repo.commit_shared()
00441 
00442         # Create second generation. It will have a file with two chunks.
00443         # Only one of the chunks will be put into the shared trees.
00444         self.repo.lock_client('client_name')
00445         self.repo.lock_shared()
00446         gen2 = self.repo.start_generation()
00447         chunk_id1 = self.repo.put_chunk_only('data')
00448         self.repo.put_chunk_in_shared_trees(chunk_id1, 'checksum')
00449         chunk_id2 = self.repo.put_chunk_only('data2')
00450         self.repo.set_file_chunks('/foo', [chunk_id1, chunk_id2])
00451         self.repo.commit_client()
00452         self.repo.commit_shared()
00453 
00454         # Do we have the right generations? And the chunk2?
00455         self.repo.open_client('client_name')
00456         self.assertEqual(len(self.repo.list_generations()), 2)
00457         self.assertTrue(self.repo.chunk_exists(chunk_id1))
00458         self.assertTrue(self.repo.chunk_exists(chunk_id2))
00459 
00460         # Remove second generation. This should remove the chunk too.
00461         self.repo.lock_client('client_name')
00462         self.repo.lock_shared()
00463         self.repo.remove_generation(gen2)
00464         self.repo.commit_client()
00465         self.repo.commit_shared()
00466 
00467         # Make sure we have only the first generation, and that the
00468         # chunks are gone.
00469         self.repo.open_client('client_name')
00470         self.assertEqual(self.repo.list_generations(), [gen1])
00471         self.assertFalse(self.repo.chunk_exists(chunk_id1))
00472         self.assertFalse(self.repo.chunk_exists(chunk_id2))
00473 
00474     def test_removing_started_generation_fails(self):
00475         self.repo.lock_client('client_name')
00476         gen = self.repo.start_generation()
00477         self.assertRaises(obnamlib.Error,
00478                           self.repo.remove_generation, gen)
00479 
00480     def test_removing_without_committing_does_not_remove(self):
00481         self.repo.lock_client('client_name')
00482         self.repo.lock_shared()
00483         gen = self.repo.start_generation()
00484         self.repo.commit_client()
00485         self.repo.commit_shared()
00486 
00487         self.repo.lock_client('client_name')
00488         self.repo.lock_shared()
00489         self.repo.remove_generation(gen)
00490         self.repo.unlock_client()
00491         self.repo.unlock_shared()
00492 
00493         self.repo.open_client('client_name')
00494         self.assertEqual(self.repo.list_generations(), [gen])
00495 
00496     def test_new_generation_has_root_dir_only(self):
00497         self.repo.lock_client('client_name')
00498         gen = self.repo.start_generation()
00499         self.assertEqual(self.repo.listdir(gen, '/'), [])
00500 
00501     def test_create_fails_unless_generation_is_started(self):
00502         self.assertRaises(obnamlib.Error, self.repo.create, None, None)
00503 
00504     def test_create_adds_file(self):
00505         self.repo.lock_client('client_name')
00506         gen = self.repo.start_generation()
00507         self.repo.create('/', self.dir_meta)
00508         self.repo.create('/foo', obnamlib.Metadata())
00509         self.assertEqual(self.repo.listdir(gen, '/'), ['foo'])
00510 
00511     def test_create_adds_two_files(self):
00512         self.repo.lock_client('client_name')
00513         gen = self.repo.start_generation()
00514         self.repo.create('/', self.dir_meta)
00515         self.repo.create('/foo', obnamlib.Metadata())
00516         self.repo.create('/bar', obnamlib.Metadata())
00517         self.assertEqual(sorted(self.repo.listdir(gen, '/')), ['bar', 'foo'])
00518 
00519     def test_create_adds_lots_of_files(self):
00520         n = 100
00521         self.repo.lock_client('client_name')
00522         gen = self.repo.start_generation()
00523         pathnames = ['/%d' % i for i in range(n)]
00524         for pathname in pathnames:
00525             self.repo.create(pathname, obnamlib.Metadata())
00526         self.assertEqual(sorted(self.repo.listdir(gen, '/')), 
00527                          sorted(os.path.basename(x) for x in pathnames))
00528 
00529     def test_create_adds_dir(self):
00530         self.repo.lock_client('client_name')
00531         gen = self.repo.start_generation()
00532         self.repo.create('/foo', self.dir_meta)
00533         self.assertEqual(self.repo.listdir(gen, '/foo'), [])
00534 
00535     def test_create_adds_dir_after_file_in_it(self):
00536         self.repo.lock_client('client_name')
00537         gen = self.repo.start_generation()
00538         self.repo.create('/foo/bar', obnamlib.Metadata())
00539         self.repo.create('/foo', self.dir_meta)
00540         self.assertEqual(self.repo.listdir(gen, '/foo'), ['bar'])
00541 
00542     def test_gets_metadata_for_dir(self):
00543         self.repo.lock_client('client_name')
00544         gen = self.repo.start_generation()
00545         self.repo.create('/foo', self.dir_meta)
00546         self.assertEqual(self.repo.get_metadata(gen, '/foo').st_mode, 
00547                          self.dir_meta.st_mode)
00548 
00549     def test_remove_removes_file(self):
00550         self.repo.lock_client('client_name')
00551         gen = self.repo.start_generation()
00552         self.repo.create('/foo', obnamlib.Metadata())
00553         self.repo.remove('/foo')
00554         self.assertEqual(self.repo.listdir(gen, '/'), [])
00555 
00556     def test_remove_removes_directory_tree(self):
00557         self.repo.lock_client('client_name')
00558         gen = self.repo.start_generation()
00559         self.repo.create('/foo/bar', obnamlib.Metadata())
00560         self.repo.remove('/foo')
00561         self.assertEqual(self.repo.listdir(gen, '/'), [])
00562 
00563     def test_get_metadata_works(self):
00564         metadata = obnamlib.Metadata()
00565         metadata.st_size = 123
00566         self.repo.lock_client('client_name')
00567         gen = self.repo.start_generation()
00568         self.repo.create('/foo', metadata)
00569         received = self.repo.get_metadata(gen, '/foo')
00570         self.assertEqual(metadata.st_size, received.st_size)
00571 
00572     def test_get_metadata_raises_exception_if_file_does_not_exist(self):
00573         self.repo.lock_client('client_name')
00574         gen = self.repo.start_generation()
00575         self.assertRaises(obnamlib.Error, self.repo.get_metadata,
00576                           gen, '/foo')
00577 
00578 
00579 class RepositoryChunkTests(unittest.TestCase):
00580 
00581     def setUp(self):
00582         self.tempdir = tempfile.mkdtemp()
00583 
00584         self.fs = obnamlib.LocalFS(self.tempdir)
00585         self.repo = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00586                                         obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00587                                         obnamlib.DEFAULT_LRU_SIZE, None,
00588                                         obnamlib.IDPATH_DEPTH,
00589                                         obnamlib.IDPATH_BITS,
00590                                         obnamlib.IDPATH_SKIP,
00591                                         time.time, 0, '')
00592         self.repo.lock_root()
00593         self.repo.add_client('client_name')
00594         self.repo.commit_root()
00595         self.repo.lock_client('client_name')
00596         self.repo.start_generation()
00597 
00598     def tearDown(self):
00599         shutil.rmtree(self.tempdir)
00600 
00601     def test_checksum_returns_checksum(self):
00602         self.assertNotEqual(self.repo.checksum('data'), None)
00603 
00604     def test_put_chunk_returns_id(self):
00605         self.repo.lock_shared()
00606         self.assertNotEqual(self.repo.put_chunk_only('data'), None)
00607         
00608     def test_get_chunk_retrieves_what_put_chunk_puts(self):
00609         self.repo.lock_shared()
00610         chunkid = self.repo.put_chunk_only('data')
00611         self.assertEqual(self.repo.get_chunk(chunkid), 'data')
00612         
00613     def test_chunk_does_not_exist(self):
00614         self.assertFalse(self.repo.chunk_exists(1234))
00615         
00616     def test_chunk_exists_after_it_is_put(self):
00617         self.repo.lock_shared()
00618         chunkid = self.repo.put_chunk_only('chunk')
00619         self.assert_(self.repo.chunk_exists(chunkid))
00620 
00621     def test_removes_chunk(self):
00622         self.repo.lock_shared()
00623         chunkid = self.repo.put_chunk_only('chunk')
00624         self.repo.remove_chunk(chunkid)
00625         self.assertFalse(self.repo.chunk_exists(chunkid))
00626 
00627     def test_silently_ignores_failure_when_removing_nonexistent_chunk(self):
00628         self.repo.lock_shared()
00629         self.assertEqual(self.repo.remove_chunk(0), None)
00630         
00631     def test_find_chunks_finds_what_put_chunk_puts(self):
00632         self.repo.lock_shared()
00633         checksum = self.repo.checksum('data')
00634         chunkid = self.repo.put_chunk_only('data')
00635         self.repo.put_chunk_in_shared_trees(chunkid, checksum)
00636         self.assertEqual(self.repo.find_chunks(checksum), [chunkid])
00637         
00638     def test_find_chunks_finds_nothing_if_nothing_is_put(self):
00639         self.assertEqual(self.repo.find_chunks('checksum'), [])
00640         
00641     def test_handles_checksum_collision(self):
00642         self.repo.lock_shared()
00643         checksum = self.repo.checksum('data')
00644         chunkid1 = self.repo.put_chunk_only('data')
00645         chunkid2 = self.repo.put_chunk_only('data')
00646         self.repo.put_chunk_in_shared_trees(chunkid1, checksum)
00647         self.repo.put_chunk_in_shared_trees(chunkid2, checksum)
00648         self.assertEqual(set(self.repo.find_chunks(checksum)),
00649                          set([chunkid1, chunkid2]))
00650 
00651     def test_returns_no_chunks_initially(self):
00652         self.assertEqual(self.repo.list_chunks(), [])
00653         
00654     def test_returns_chunks_after_they_exist(self):
00655         self.repo.lock_shared()
00656         checksum = self.repo.checksum('data')
00657         chunkids = []
00658         for i in range(2):
00659             chunkids.append(self.repo.put_chunk_only('data'))
00660         self.assertEqual(sorted(self.repo.list_chunks()), sorted(chunkids))
00661 
00662 
00663 class RepositoryGetSetChunksTests(unittest.TestCase):
00664 
00665     def setUp(self):
00666         self.tempdir = tempfile.mkdtemp()
00667 
00668         self.fs = obnamlib.LocalFS(self.tempdir)
00669         self.repo = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00670                                         obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00671                                         obnamlib.DEFAULT_LRU_SIZE, None,
00672                                         obnamlib.IDPATH_DEPTH,
00673                                         obnamlib.IDPATH_BITS,
00674                                         obnamlib.IDPATH_SKIP,
00675                                         time.time, 0, '')
00676         self.repo.lock_root()
00677         self.repo.add_client('client_name')
00678         self.repo.commit_root()
00679         self.repo.lock_client('client_name')
00680         self.gen = self.repo.start_generation()
00681         self.repo.create('/foo', obnamlib.Metadata())
00682 
00683     def tearDown(self):
00684         shutil.rmtree(self.tempdir)
00685 
00686     def test_file_has_no_chunks(self):
00687         self.assertEqual(self.repo.get_file_chunks(self.gen, '/foo'), [])
00688 
00689     def test_sets_chunks_for_file(self):
00690         self.repo.set_file_chunks('/foo', [1, 2])
00691         chunkids = self.repo.get_file_chunks(self.gen, '/foo')
00692         self.assertEqual(sorted(chunkids), [1, 2])
00693 
00694     def test_appends_chunks_to_empty_list(self):
00695         self.repo.append_file_chunks('/foo', [1, 2])
00696         chunkids = self.repo.get_file_chunks(self.gen, '/foo')
00697         self.assertEqual(sorted(chunkids), [1, 2])
00698 
00699     def test_appends_chunks_to_nonempty_list(self):
00700         self.repo.append_file_chunks('/foo', [1, 2])
00701         self.repo.append_file_chunks('/foo', [3, 4])
00702         chunkids = self.repo.get_file_chunks(self.gen, '/foo')
00703         self.assertEqual(sorted(chunkids), [1, 2, 3, 4])
00704 
00705 
00706 class RepositoryGenspecTests(unittest.TestCase):
00707 
00708     def setUp(self):
00709         self.tempdir = tempfile.mkdtemp()
00710 
00711         repodir = os.path.join(self.tempdir, 'repo')
00712         os.mkdir(repodir)
00713         fs = obnamlib.LocalFS(repodir)
00714         self.repo = obnamlib.Repository(fs, obnamlib.DEFAULT_NODE_SIZE,
00715                                         obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00716                                         obnamlib.DEFAULT_LRU_SIZE, None,
00717                                         obnamlib.IDPATH_DEPTH,
00718                                         obnamlib.IDPATH_BITS,
00719                                         obnamlib.IDPATH_SKIP,
00720                                         time.time, 0, '')
00721         self.repo.lock_root()
00722         self.repo.add_client('client_name')
00723         self.repo.commit_root()
00724         self.repo.lock_client('client_name')
00725         self.repo.lock_shared()
00726 
00727     def tearDown(self):
00728         shutil.rmtree(self.tempdir)
00729 
00730     def backup(self):
00731         gen = self.repo.start_generation()
00732         self.repo.commit_client()
00733         self.repo.commit_shared()
00734         self.repo.lock_client('client_name')
00735         self.repo.lock_shared()
00736         return gen
00737 
00738     def test_latest_raises_error_if_there_are_no_generations(self):
00739         self.assertRaises(obnamlib.Error, self.repo.genspec, 'latest')
00740 
00741     def test_latest_returns_only_generation(self):
00742         gen = self.backup()
00743         self.assertEqual(self.repo.genspec('latest'), gen)
00744 
00745     def test_latest_returns_newest_generation(self):
00746         self.backup()
00747         gen = self.backup()
00748         self.assertEqual(self.repo.genspec('latest'), gen)
00749 
00750     def test_other_spec_returns_itself(self):
00751         gen = self.backup()
00752         self.assertEqual(self.repo.genspec(str(gen)), gen)
00753 
00754     def test_noninteger_spec_raises_error(self):
00755         gen = self.backup()
00756         self.assertNotEqual(gen, 'foo')
00757         self.assertRaises(obnamlib.Error, self.repo.genspec, 'foo')
00758 
00759     def test_nonexistent_spec_raises_error(self):
00760         self.backup()
00761         self.assertRaises(obnamlib.Error, self.repo.genspec, 1234)
00762 
00763 
00764 class RepositoryWalkTests(unittest.TestCase):
00765 
00766     def setUp(self):
00767         self.tempdir = tempfile.mkdtemp()
00768 
00769         self.fs = obnamlib.LocalFS(self.tempdir)
00770         self.repo = obnamlib.Repository(self.fs, obnamlib.DEFAULT_NODE_SIZE,
00771                                         obnamlib.DEFAULT_UPLOAD_QUEUE_SIZE,
00772                                         obnamlib.DEFAULT_LRU_SIZE, None,
00773                                         obnamlib.IDPATH_DEPTH,
00774                                         obnamlib.IDPATH_BITS,
00775                                         obnamlib.IDPATH_SKIP,
00776                                         time.time, 0, '')
00777         self.repo.lock_root()
00778         self.repo.add_client('client_name')
00779         self.repo.commit_root()
00780 
00781         self.dir_meta = obnamlib.Metadata()
00782         self.dir_meta.st_mode = stat.S_IFDIR | 0777
00783         
00784         self.file_meta = obnamlib.Metadata()
00785         self.file_meta.st_mode = stat.S_IFREG | 0644
00786         
00787         self.repo.lock_client('client_name')
00788         self.repo.lock_shared()
00789         self.gen = self.repo.start_generation()
00790         
00791         self.repo.create('/', self.dir_meta)
00792         self.repo.create('/foo', self.dir_meta)
00793         self.repo.create('/foo/bar', self.file_meta)
00794         
00795         self.repo.commit_client()
00796         self.repo.open_client('client_name')
00797 
00798     def tearDown(self):
00799         shutil.rmtree(self.tempdir)
00800 
00801     def test_walk_find_everything(self):
00802         found = list(self.repo.walk(self.gen, '/'))
00803         self.assertEqual(found,
00804                          [('/', self.dir_meta),
00805                           ('/foo', self.dir_meta),
00806                           ('/foo/bar', self.file_meta)])
00807 
00808     def test_walk_find_depth_first(self):
00809         found = list(self.repo.walk(self.gen, '/', depth_first=True))
00810         self.assertEqual(found,
00811                          [('/foo/bar', self.file_meta),
00812                           ('/foo', self.dir_meta),
00813                           ('/', self.dir_meta)])
00814