|
1 | 1 | """Tests for the Azure AzMultiPartUpload class."""
|
2 | 2 |
|
3 | 3 | import base64
|
4 |
| -import unittest |
5 | 4 | from unittest.mock import MagicMock, patch
|
6 | 5 |
|
7 |
| -# Conditional import for Azure support |
8 |
| -try: |
9 |
| - from odc.geo.cog._az import AzMultiPartUpload |
| 6 | +import pytest |
10 | 7 |
|
11 |
| - HAVE_AZURE = True |
12 |
| -except ImportError: |
13 |
| - AzMultiPartUpload = None |
14 |
| - HAVE_AZURE = False |
| 8 | +pytest.importorskip("odc.geo.cog._az") |
| 9 | +from odc.geo.cog._az import AzMultiPartUpload # noqa: E402 |
15 | 10 |
|
16 | 11 |
|
17 |
| -def require_azure(test_func): |
18 |
| - """Decorator to skip tests if Azure dependencies are not installed.""" |
19 |
| - return unittest.skipUnless(HAVE_AZURE, "Azure dependencies are not installed")( |
20 |
| - test_func |
| 12 | +@pytest.fixture |
| 13 | +def azure_mpu(): |
| 14 | + """Fixture for initializing AzMultiPartUpload.""" |
| 15 | + account_url = "https://account_name.blob.core.windows.net" |
| 16 | + return AzMultiPartUpload(account_url, "container", "some.blob", None) |
| 17 | + |
| 18 | + |
| 19 | +def test_mpu_init(azure_mpu): |
| 20 | + """Basic test for AzMultiPartUpload initialization.""" |
| 21 | + assert azure_mpu.account_url == "https://account_name.blob.core.windows.net" |
| 22 | + assert azure_mpu.container == "container" |
| 23 | + assert azure_mpu.blob == "some.blob" |
| 24 | + assert azure_mpu.credential is None |
| 25 | + |
| 26 | + |
| 27 | +@patch("odc.geo.cog._az.BlobServiceClient") |
| 28 | +def test_azure_multipart_upload(mock_blob_service_client): |
| 29 | + """Test the full Azure AzMultiPartUpload functionality.""" |
| 30 | + # Mock Azure Blob SDK client structure |
| 31 | + mock_blob_client = MagicMock() |
| 32 | + mock_container_client = MagicMock() |
| 33 | + mock_blob_service_client.return_value.get_container_client.return_value = ( |
| 34 | + mock_container_client |
| 35 | + ) |
| 36 | + mock_container_client.get_blob_client.return_value = mock_blob_client |
| 37 | + |
| 38 | + # Simulate return values for Azure Blob SDK methods |
| 39 | + mock_blob_client.get_blob_properties.return_value.etag = "mock-etag" |
| 40 | + |
| 41 | + # Test parameters |
| 42 | + account_url = "https://mockaccount.blob.core.windows.net" |
| 43 | + container = "mock-container" |
| 44 | + blob = "mock-blob" |
| 45 | + credential = "mock-sas-token" |
| 46 | + |
| 47 | + # Create an instance of AzMultiPartUpload and call its methods |
| 48 | + azure_upload = AzMultiPartUpload(account_url, container, blob, credential) |
| 49 | + upload_id = azure_upload.initiate() |
| 50 | + part1 = azure_upload.write_part(1, b"first chunk of data") |
| 51 | + part2 = azure_upload.write_part(2, b"second chunk of data") |
| 52 | + etag = azure_upload.finalise([part1, part2]) |
| 53 | + |
| 54 | + # Define block IDs |
| 55 | + block_id1 = base64.b64encode(b"block-1").decode("utf-8") |
| 56 | + block_id2 = base64.b64encode(b"block-2").decode("utf-8") |
| 57 | + |
| 58 | + # Verify the results |
| 59 | + assert upload_id == "azure-block-upload" |
| 60 | + assert etag == "mock-etag" |
| 61 | + |
| 62 | + # Verify BlobServiceClient instantiation |
| 63 | + mock_blob_service_client.assert_called_once_with( |
| 64 | + account_url=account_url, credential=credential |
21 | 65 | )
|
22 | 66 |
|
| 67 | + # Verify stage_block calls |
| 68 | + mock_blob_client.stage_block.assert_any_call( |
| 69 | + block_id=block_id1, data=b"first chunk of data" |
| 70 | + ) |
| 71 | + mock_blob_client.stage_block.assert_any_call( |
| 72 | + block_id=block_id2, data=b"second chunk of data" |
| 73 | + ) |
23 | 74 |
|
24 |
| -class TestAzMultiPartUpload(unittest.TestCase): |
25 |
| - """Test the AzMultiPartUpload class.""" |
26 |
| - |
27 |
| - @require_azure |
28 |
| - def test_mpu_init(self): |
29 |
| - """Basic test for AzMultiPartUpload initialization.""" |
30 |
| - account_url = "https://account_name.blob.core.windows.net" |
31 |
| - mpu = AzMultiPartUpload(account_url, "container", "some.blob", None) |
32 |
| - |
33 |
| - self.assertEqual(mpu.account_url, account_url) |
34 |
| - self.assertEqual(mpu.container, "container") |
35 |
| - self.assertEqual(mpu.blob, "some.blob") |
36 |
| - self.assertIsNone(mpu.credential) |
37 |
| - |
38 |
| - @require_azure |
39 |
| - @patch("odc.geo.cog._az.BlobServiceClient") |
40 |
| - def test_azure_multipart_upload(self, mock_blob_service_client): |
41 |
| - """Test the full Azure AzMultiPartUpload functionality.""" |
42 |
| - # Arrange - Mock Azure Blob SDK client structure |
43 |
| - mock_blob_client = MagicMock() |
44 |
| - mock_container_client = MagicMock() |
45 |
| - mock_blob_service_client.return_value.get_container_client.return_value = ( |
46 |
| - mock_container_client |
47 |
| - ) |
48 |
| - mock_container_client.get_blob_client.return_value = mock_blob_client |
49 |
| - |
50 |
| - # Simulate return values for Azure Blob SDK methods |
51 |
| - mock_blob_client.get_blob_properties.return_value.etag = "mock-etag" |
52 |
| - |
53 |
| - # Test parameters |
54 |
| - account_url = "https://mockaccount.blob.core.windows.net" |
55 |
| - container = "mock-container" |
56 |
| - blob = "mock-blob" |
57 |
| - credential = "mock-sas-token" |
58 |
| - |
59 |
| - # Act |
60 |
| - azure_upload = AzMultiPartUpload(account_url, container, blob, credential) |
61 |
| - upload_id = azure_upload.initiate() |
62 |
| - part1 = azure_upload.write_part(1, b"first chunk of data") |
63 |
| - part2 = azure_upload.write_part(2, b"second chunk of data") |
64 |
| - etag = azure_upload.finalise([part1, part2]) |
65 |
| - |
66 |
| - # Correctly calculate block IDs |
67 |
| - block_id1 = base64.b64encode(b"block-1").decode("utf-8") |
68 |
| - block_id2 = base64.b64encode(b"block-2").decode("utf-8") |
69 |
| - |
70 |
| - # Assert |
71 |
| - self.assertEqual(upload_id, "azure-block-upload") |
72 |
| - self.assertEqual(etag, "mock-etag") |
73 |
| - |
74 |
| - # Verify BlobServiceClient instantiation |
75 |
| - mock_blob_service_client.assert_called_once_with( |
76 |
| - account_url=account_url, credential=credential |
77 |
| - ) |
78 |
| - |
79 |
| - # Verify stage_block calls |
80 |
| - mock_blob_client.stage_block.assert_any_call( |
81 |
| - block_id=block_id1, data=b"first chunk of data" |
82 |
| - ) |
83 |
| - mock_blob_client.stage_block.assert_any_call( |
84 |
| - block_id=block_id2, data=b"second chunk of data" |
85 |
| - ) |
86 |
| - |
87 |
| - # Verify commit_block_list was called correctly |
88 |
| - block_list = mock_blob_client.commit_block_list.call_args[0][0] |
89 |
| - self.assertEqual(len(block_list), 2) |
90 |
| - self.assertEqual(block_list[0].id, block_id1) |
91 |
| - self.assertEqual(block_list[1].id, block_id2) |
92 |
| - mock_blob_client.commit_block_list.assert_called_once() |
93 |
| - |
94 |
| - |
95 |
| -if __name__ == "__main__": |
96 |
| - unittest.main() |
| 75 | + # Verify commit_block_list was called correctly |
| 76 | + block_list = mock_blob_client.commit_block_list.call_args[0][0] |
| 77 | + assert len(block_list) == 2 |
| 78 | + assert block_list[0].id == block_id1 |
| 79 | + assert block_list[1].id == block_id2 |
| 80 | + mock_blob_client.commit_block_list.assert_called_once() |
0 commit comments