diff --git a/tests/integration/test_aws_cli_commands.py b/tests/integration/test_aws_cli_commands.py index a5ed2d0..ab8aeff 100644 --- a/tests/integration/test_aws_cli_commands.py +++ b/tests/integration/test_aws_cli_commands.py @@ -130,17 +130,23 @@ class TestSyncCommand: # Mock service methods mock_service.storage.list.return_value = [] # No existing files - mock_service.put.return_value = PutSummary( - operation="create_reference", - bucket="test-bucket", - key="backup/file.zip.delta", - original_name="file.zip", - file_size=8, - file_sha256="ghi789", - delta_size=None, - delta_ratio=None, - ref_key=None, - ) + # Mock list_objects to raise NotImplementedError so it falls back to list() + mock_service.storage.list_objects.side_effect = NotImplementedError() + + # Mock service.put to avoid actual execution + def mock_put(local_path, delta_space, max_ratio=None): + return PutSummary( + operation="create_reference", + bucket="test-bucket", + key=f"{delta_space.prefix}/{local_path.name}.delta" if delta_space.prefix else f"{local_path.name}.delta", + original_name=local_path.name, + file_size=local_path.stat().st_size, + file_sha256="ghi789", + delta_size=None, + delta_ratio=None, + ref_key=None, + ) + mock_service.put.side_effect = mock_put with patch("deltaglider.app.cli.main.create_service", return_value=mock_service): result = runner.invoke(cli, ["sync", str(test_dir), "s3://test-bucket/backup/"]) @@ -175,6 +181,8 @@ class TestSyncCommand: metadata={}, ), ] + # Mock list_objects to raise NotImplementedError so it falls back to list() + mock_service.storage.list_objects.side_effect = NotImplementedError() mock_service.storage.head.side_effect = [ None, # file1.zip doesn't exist Mock(), # file1.zip.delta exists diff --git a/tests/integration/test_bucket_management.py b/tests/integration/test_bucket_management.py index f1e3e09..df547c8 100644 --- a/tests/integration/test_bucket_management.py +++ b/tests/integration/test_bucket_management.py @@ -255,7 +255,7 @@ class TestBucketManagement: call_count = {"value": 0} - def fake_get_bucket_stats(_: Any, bucket: str, mode: str) -> BucketStats: + def fake_get_bucket_stats(_: Any, bucket: str, mode: str, use_cache: bool = True, refresh_cache: bool = False) -> BucketStats: call_count["value"] += 1 assert bucket == "bucket1" if mode == "detailed": @@ -271,24 +271,20 @@ class TestBucketManagement: assert result_quick is quick_stats assert call_count["value"] == 1 - # Second quick call should hit cache + # Second quick call - caching is now done in _get_bucket_stats (S3-based) + # So each call goes through _get_bucket_stats (which handles caching internally) assert client.get_bucket_stats("bucket1") is quick_stats - assert call_count["value"] == 1 + assert call_count["value"] == 2 # Detailed call triggers new computation result_detailed = client.get_bucket_stats("bucket1", mode="detailed") assert result_detailed is detailed_stats - assert call_count["value"] == 2 - - # Quick call after detailed uses detailed cached value (more accurate) - assert client.get_bucket_stats("bucket1") is detailed_stats - assert call_count["value"] == 2 - - # Clearing the cache should force recomputation - client.clear_cache() - assert client.get_bucket_stats("bucket1") is quick_stats assert call_count["value"] == 3 + # Quick call - each mode has its own cache in _get_bucket_stats + assert client.get_bucket_stats("bucket1") is quick_stats + assert call_count["value"] == 4 + def test_bucket_methods_without_boto3_client(self): """Test that bucket methods raise NotImplementedError when storage doesn't support it.""" service = create_service() diff --git a/tests/integration/test_client.py b/tests/integration/test_client.py index 8d781ad..9286f81 100644 --- a/tests/integration/test_client.py +++ b/tests/integration/test_client.py @@ -43,7 +43,7 @@ class MockStorage: if obj_head is not None: yield obj_head - def list_objects(self, bucket, prefix="", delimiter="", max_keys=1000, start_after=None): + def list_objects(self, bucket, prefix="", delimiter="", max_keys=1000, start_after=None, continuation_token=None): """Mock list_objects operation for S3 features.""" objects = [] common_prefixes = set() diff --git a/tests/integration/test_stats_command.py b/tests/integration/test_stats_command.py index 2c390c3..8d5341d 100644 --- a/tests/integration/test_stats_command.py +++ b/tests/integration/test_stats_command.py @@ -49,7 +49,7 @@ class TestStatsCommand: assert output["direct_objects"] == 3 # Verify client was called correctly - mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick") + mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick", use_cache=True, refresh_cache=False) def test_stats_json_output_detailed(self): """Test stats command with detailed JSON output.""" @@ -77,7 +77,7 @@ class TestStatsCommand: assert output["average_compression_ratio"] == 0.95 # Verify detailed flag was passed - mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="detailed") + mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="detailed", use_cache=True, refresh_cache=False) def test_stats_json_output_sampled(self): """Test stats command with sampled JSON output.""" @@ -101,7 +101,7 @@ class TestStatsCommand: result = runner.invoke(cli, ["stats", "test-bucket", "--sampled", "--json"]) assert result.exit_code == 0 - mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="sampled") + mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="sampled", use_cache=True, refresh_cache=False) def test_stats_sampled_and_detailed_conflict(self): """--sampled and --detailed flags must be mutually exclusive.""" @@ -190,7 +190,7 @@ class TestStatsCommand: assert result.exit_code == 0 # Verify bucket name was parsed correctly from S3 URL - mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick") + mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick", use_cache=True, refresh_cache=False) def test_stats_with_s3_url_trailing_slash(self): """Test stats command with s3:// URL format with trailing slash.""" @@ -215,7 +215,7 @@ class TestStatsCommand: assert result.exit_code == 0 # Verify bucket name was parsed correctly from S3 URL with trailing slash - mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick") + mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick", use_cache=True, refresh_cache=False) def test_stats_with_s3_url_with_prefix(self): """Test stats command with s3:// URL format with prefix (should ignore prefix).""" @@ -240,4 +240,4 @@ class TestStatsCommand: assert result.exit_code == 0 # Verify only bucket name was extracted, prefix ignored - mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick") + mock_client.get_bucket_stats.assert_called_once_with("test-bucket", mode="quick", use_cache=True, refresh_cache=False)