| 
					
				 | 
			
			
				@@ -12,6 +12,7 @@ from ..crypto.key import PlaintextKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from ..helpers import IntegrityError 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from ..repoobj import RepoObj 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .hashindex import H 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .repository import fchunk, pdchunk 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .key import TestKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -74,9 +75,9 @@ class TestRepositoryCache: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def repository(self, tmpdir): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.repository_location = os.path.join(str(tmpdir), "repository") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         with Repository(self.repository_location, exclusive=True, create=True) as repository: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            repository.put(H(1), b"1234") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            repository.put(H(2), b"5678") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            repository.put(H(3), bytes(100)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            repository.put(H(1), fchunk(b"1234")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            repository.put(H(2), fchunk(b"5678")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            repository.put(H(3), fchunk(bytes(100))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             yield repository 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @pytest.fixture 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -85,19 +86,55 @@ class TestRepositoryCache: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def test_simple(self, cache: RepositoryCache): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Single get()s are not cached, since they are used for unique objects like archives. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert cache.get(H(1)) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(cache.get(H(1))) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.misses == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.hits == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert list(cache.get_many([H(1)])) == [b"1234"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)])] == [b"1234"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.hits == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert list(cache.get_many([H(1)])) == [b"1234"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)])] == [b"1234"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.hits == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert cache.get(H(1)) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(cache.get(H(1))) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def test_meta(self, cache: RepositoryCache): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # same as test_simple, but not reading the chunk data (metadata only). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        # Single get()s are not cached, since they are used for unique objects like archives. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(cache.get(H(1), read_data=False)) == b"" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)], read_data=False)] == [b""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)], read_data=False)] == [b""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(cache.get(H(1), read_data=False)) == b"" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def test_mixed(self, cache: RepositoryCache): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)], read_data=False)] == [b""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)], read_data=True)] == [b"1234"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)], read_data=False)] == [b""] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert cache.hits == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1)], read_data=True)] == [b"1234"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.hits == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -105,11 +142,11 @@ class TestRepositoryCache: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         def query_size_limit(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             cache.size_limit = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert list(cache.get_many([H(1), H(2)])) == [b"1234", b"5678"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert [pdchunk(ch) for ch in cache.get_many([H(1), H(2)])] == [b"1234", b"5678"] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.misses == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.evictions == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         iterator = cache.get_many([H(1), H(3), H(2)]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert next(iterator) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(next(iterator)) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Force cache to back off 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         qsl = cache.query_size_limit 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -120,11 +157,11 @@ class TestRepositoryCache: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.evictions == 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert H(1) not in cache.cache 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert H(2) not in cache.cache 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert next(iterator) == bytes(100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(next(iterator)) == bytes(100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.slow_misses == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # Since H(2) was in the cache when we called get_many(), but has 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # been evicted during iterating the generator, it will be a slow miss. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert next(iterator) == b"5678" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(next(iterator)) == b"5678" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert cache.slow_misses == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def test_enospc(self, cache: RepositoryCache): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -145,16 +182,16 @@ class TestRepositoryCache: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 pass 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         iterator = cache.get_many([H(1), H(2), H(3)]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert next(iterator) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(next(iterator)) == b"1234" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         with patch("builtins.open", enospc_open): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            assert next(iterator) == b"5678" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            assert pdchunk(next(iterator)) == b"5678" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             assert cache.enospc == 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # We didn't patch query_size_limit which would set size_limit to some low 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             # value, so nothing was actually evicted. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             assert cache.evictions == 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        assert next(iterator) == bytes(100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert pdchunk(next(iterator)) == bytes(100) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @pytest.fixture 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def key(self, repository, monkeypatch): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -193,7 +230,8 @@ class TestRepositoryCache: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         iterator = decrypted_cache.get_many([H1, H2, H3]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         assert next(iterator) == (4, b"1234") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        with open(decrypted_cache.key_filename(H2), "a+b") as fd: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pkey = decrypted_cache.prefixed_key(H2, complete=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        with open(decrypted_cache.key_filename(pkey), "a+b") as fd: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             fd.seek(-1, io.SEEK_END) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             corrupted = (int.from_bytes(fd.read(), "little") ^ 2).to_bytes(1, "little") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             fd.seek(-1, io.SEEK_END) 
			 |