Skip to content

Commit e7cf320

Browse files
[Storage][Test] Test multiple service versions (Azure#19039)
* adding infra for specifying service version from env var or by default * changes for blob to show usage * updates for storage-queue * adding bens comment and assert policy for blob * removing * key change * fixing way service version is read * fixing an issue * adding skipif the sv is too low
1 parent 0c573e6 commit e7cf320

File tree

8 files changed

+182
-7
lines changed

8 files changed

+182
-7
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from datetime import datetime
2+
from enum import Enum
3+
import os
4+
5+
6+
class ServiceVersion(str, Enum):
7+
8+
V2019_02_02 = "2019-02-02"
9+
V2019_07_07 = "2019-07-07"
10+
V2019_10_10 = "2019-10-10"
11+
V2019_12_12 = "2019-12-12"
12+
V2020_02_10 = "2020-02-10"
13+
V2020_04_08 = "2020-04-08"
14+
V2020_06_12 = "2020-06-12"
15+
V2020_08_04 = "2020-08-04"
16+
17+
18+
service_version_map = {
19+
"V2019_02_02": ServiceVersion.V2019_02_02,
20+
"V2019_07_07": ServiceVersion.V2019_07_07,
21+
"V2019_10_10": ServiceVersion.V2019_10_10,
22+
"V2019_12_12": ServiceVersion.V2019_12_12,
23+
"V2020_02_10": ServiceVersion.V2020_02_10,
24+
"V2020_04_08": ServiceVersion.V2020_04_08,
25+
"V2020_06_12": ServiceVersion.V2020_06_12,
26+
"V2020_08_04": ServiceVersion.V2020_08_04,
27+
"LATEST": ServiceVersion.V2020_08_04,
28+
"LATEST_PLUS_1": ServiceVersion.V2020_06_12
29+
}
30+
31+
32+
def is_version_before(test_version):
33+
""" Return True if the current version is after a given one or if the
34+
service version is not set.
35+
"""
36+
current_version = service_version_map.get(os.environ.get("AZURE_LIVE_TEST_SERVICE_VERSION"))
37+
if not current_version:
38+
return True
39+
current_version_data = datetime.strptime(current_version, "%Y-%m-%d")
40+
test_version_minimum = datetime.strptime(test_version, "%Y-%m-%d")
41+
ret = current_version_data < test_version_minimum
42+
return ret

sdk/storage/azure-storage-blob/tests/_shared/testcase.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import zlib
1818
import math
1919
import sys
20-
import string
20+
import os
2121
import random
2222
import re
2323
import logging
@@ -34,6 +34,7 @@
3434
except ImportError:
3535
from io import StringIO
3636

37+
from azure.core.pipeline.policies import SansIOHTTPPolicy
3738
from azure.core.exceptions import ResourceNotFoundError, HttpResponseError
3839
from azure.core.credentials import AccessToken
3940
from azure.storage.blob import generate_account_sas, AccountSasPermissions, ResourceTypes
@@ -50,6 +51,8 @@
5051
except ImportError:
5152
from devtools_testutils import mgmt_settings_fake as settings
5253

54+
from .service_versions import service_version_map
55+
5356
import pytest
5457

5558

@@ -310,6 +313,32 @@ def generate_sas_token(self):
310313
def generate_fake_token(self):
311314
return FakeTokenCredential()
312315

316+
def _get_service_version(self, **kwargs):
317+
env_version = service_version_map.get(os.environ.get("AZURE_LIVE_TEST_SERVICE_VERSION","LATEST"))
318+
return kwargs.pop("service_version", env_version)
319+
320+
def create_storage_client(self, client, *args, **kwargs):
321+
kwargs["api_version"] = self._get_service_version(**kwargs)
322+
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
323+
return client(*args, **kwargs)
324+
325+
def create_storage_client_from_conn_str(self, client, *args, **kwargs):
326+
kwargs["api_version"] = self._get_service_version(**kwargs)
327+
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
328+
return client.from_connection_string(*args, **kwargs)
329+
330+
331+
class ApiVersionAssertPolicy(SansIOHTTPPolicy):
332+
"""
333+
Assert the ApiVersion is set properly on the response
334+
"""
335+
336+
def __init__(self, api_version):
337+
self.api_version = api_version
338+
339+
def on_request(self, request):
340+
assert request.http_request.headers['x-ms-version'] == self.api_version
341+
313342

314343
def not_for_emulator(test):
315344
def skip_test_if_targeting_emulator(self):

sdk/storage/azure-storage-blob/tests/test_blob_tags.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
BlobBlock, generate_account_sas, ResourceTypes, AccountSasPermissions, generate_container_sas,
2626
ContainerSasPermissions, BlobClient, generate_blob_sas, BlobSasPermissions)
2727

28+
from _shared.service_versions import is_version_before, ServiceVersion
29+
2830
#------------------------------------------------------------------------------
2931

3032
TEST_CONTAINER_PREFIX = 'container'
@@ -34,7 +36,7 @@
3436
class StorageBlobTagsTest(StorageTestCase):
3537

3638
def _setup(self, storage_account, key):
37-
self.bsc = BlobServiceClient(self.account_url(storage_account, "blob"), credential=key)
39+
self.bsc = self.create_storage_client(BlobServiceClient, self.account_url(storage_account, "blob"), credential=key)
3840
self.container_name = self.get_resource_name("container")
3941
if self.is_live:
4042
container = self.bsc.get_container_client(self.container_name)
@@ -90,6 +92,7 @@ def _create_container(self, prefix="container"):
9092

9193
#-- test cases for blob tags ----------------------------------------------
9294

95+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
9396
@GlobalResourceGroupPreparer()
9497
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
9598
def test_set_blob_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -103,6 +106,7 @@ def test_set_blob_tags(self, resource_group, location, storage_account, storage_
103106
# Assert
104107
self.assertIsNotNone(resp)
105108

109+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
106110
@pytest.mark.playback_test_only
107111
@GlobalStorageAccountPreparer()
108112
def test_set_blob_tags_with_lease(self, resource_group, location, storage_account, storage_account_key):
@@ -126,6 +130,7 @@ def test_set_blob_tags_with_lease(self, resource_group, location, storage_accoun
126130

127131
blob_client.delete_blob(lease=lease)
128132

133+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
129134
@pytest.mark.playback_test_only
130135
@GlobalStorageAccountPreparer()
131136
def test_set_blob_tags_for_a_version(self, resource_group, location, storage_account, storage_account_key):
@@ -142,6 +147,7 @@ def test_set_blob_tags_for_a_version(self, resource_group, location, storage_acc
142147
# Assert
143148
self.assertIsNotNone(resp)
144149

150+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
145151
@GlobalResourceGroupPreparer()
146152
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
147153
def test_get_blob_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -160,6 +166,7 @@ def test_get_blob_tags(self, resource_group, location, storage_account, storage_
160166
for key, value in resp.items():
161167
self.assertEqual(tags[key], value)
162168

169+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
163170
@GlobalResourceGroupPreparer()
164171
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
165172
def test_get_blob_tags_for_a_snapshot(self, resource_group, location, storage_account, storage_account_key):
@@ -178,6 +185,7 @@ def test_get_blob_tags_for_a_snapshot(self, resource_group, location, storage_ac
178185
for key, value in resp.items():
179186
self.assertEqual(tags[key], value)
180187

188+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
181189
@GlobalResourceGroupPreparer()
182190
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
183191
def test_upload_block_blob_with_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -191,6 +199,7 @@ def test_upload_block_blob_with_tags(self, resource_group, location, storage_acc
191199
self.assertIsNotNone(resp)
192200
self.assertEqual(len(resp), 3)
193201

202+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
194203
@GlobalResourceGroupPreparer()
195204
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
196205
def test_get_blob_properties_returns_tags_num(self, resource_group, location, storage_account, storage_account_key):
@@ -206,6 +215,7 @@ def test_get_blob_properties_returns_tags_num(self, resource_group, location, st
206215
self.assertEqual(resp.tag_count, len(tags))
207216
self.assertEqual(downloaded.properties.tag_count, len(tags))
208217

218+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
209219
@GlobalResourceGroupPreparer()
210220
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
211221
def test_create_append_blob_with_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -219,6 +229,7 @@ def test_create_append_blob_with_tags(self, resource_group, location, storage_ac
219229
self.assertIsNotNone(resp)
220230
self.assertEqual(len(resp), 3)
221231

232+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
222233
@GlobalResourceGroupPreparer()
223234
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
224235
def test_create_page_blob_with_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -232,6 +243,7 @@ def test_create_page_blob_with_tags(self, resource_group, location, storage_acco
232243
self.assertIsNotNone(resp)
233244
self.assertEqual(len(resp), 3)
234245

246+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
235247
@GlobalResourceGroupPreparer()
236248
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
237249
def test_commit_block_list_with_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -255,6 +267,7 @@ def test_commit_block_list_with_tags(self, resource_group, location, storage_acc
255267
self.assertIsNotNone(resp)
256268
self.assertEqual(len(resp), len(tags))
257269

270+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
258271
@GlobalResourceGroupPreparer()
259272
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
260273
def test_start_copy_from_url_with_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -284,6 +297,7 @@ def test_start_copy_from_url_with_tags(self, resource_group, location, storage_a
284297
self.assertIsNotNone(resp)
285298
self.assertEqual(len(resp), len(tags))
286299

300+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
287301
@GlobalResourceGroupPreparer()
288302
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
289303
def test_list_blobs_returns_tags(self, resource_group, location, storage_account, storage_account_key):
@@ -299,6 +313,7 @@ def test_list_blobs_returns_tags(self, resource_group, location, storage_account
299313
for key, value in blob.tags.items():
300314
self.assertEqual(tags[key], value)
301315

316+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
302317
@pytest.mark.playback_test_only
303318
@GlobalStorageAccountPreparer()
304319
def test_filter_blobs(self, resource_group, location, storage_account, storage_account_key):
@@ -328,6 +343,7 @@ def test_filter_blobs(self, resource_group, location, storage_account, storage_a
328343
self.assertEqual(items_on_page2[0]['tags']['tag1'], 'firsttag')
329344
self.assertEqual(items_on_page2[0]['tags']['tag2'], 'secondtag')
330345

346+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
331347
@pytest.mark.live_test_only
332348
@GlobalResourceGroupPreparer()
333349
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
@@ -360,6 +376,7 @@ def test_filter_blobs_using_account_sas(self, resource_group, location, storage_
360376
items_on_page1 = list(first_page)
361377
self.assertEqual(1, len(items_on_page1))
362378

379+
@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
363380
@pytest.mark.live_test_only
364381
@GlobalResourceGroupPreparer()
365382
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from enum import Enum
2+
3+
4+
class ServiceVersion(str, Enum):
5+
6+
V2019_02_02 = "2019-02-02"
7+
V2019_07_07 = "2019-07-07"
8+
V2019_10_10 = "2019-10-10"
9+
V2019_12_12 = "2019-12-12"
10+
V2020_02_10 = "2020-02-10"
11+
V2020_04_08 = "2020-04-08"
12+
V2020_06_12 = "2020-06-12"
13+
V2020_08_04 = "2020-08-04"
14+
15+
16+
service_version_map = {
17+
"V2019_02_02": ServiceVersion.V2019_02_02,
18+
"V2019_07_07": ServiceVersion.V2019_07_07,
19+
"V2019_10_10": ServiceVersion.V2019_10_10,
20+
"V2019_12_12": ServiceVersion.V2019_12_12,
21+
"V2020_02_10": ServiceVersion.V2020_02_10,
22+
"V2020_04_08": ServiceVersion.V2020_04_08,
23+
"V2020_06_12": ServiceVersion.V2020_06_12,
24+
"V2020_08_04": ServiceVersion.V2020_08_04,
25+
"LATEST": ServiceVersion.V2020_08_04,
26+
"LATEST_PLUS_1": ServiceVersion.V2020_06_12
27+
}

sdk/storage/azure-storage-queue/tests/_shared/testcase.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
except ImportError:
3535
from io import StringIO
3636

37+
from azure.core.pipeline.policies import SansIOHTTPPolicy
3738
from azure.core.exceptions import ResourceNotFoundError, HttpResponseError
3839
from azure.core.credentials import AccessToken
3940
from azure.storage.queue import generate_account_sas, AccountSasPermissions, ResourceTypes
@@ -52,6 +53,8 @@
5253

5354
import pytest
5455

56+
from .service_versions import service_version_map
57+
5558

5659
LOGGING_FORMAT = '%(asctime)s %(name)-20s %(levelname)-5s %(message)s'
5760
os.environ['AZURE_STORAGE_ACCOUNT_NAME'] = STORAGE_ACCOUNT_NAME
@@ -310,13 +313,39 @@ def generate_sas_token(self):
310313
def generate_fake_token(self):
311314
return FakeTokenCredential()
312315

316+
def _get_service_version(self, **kwargs):
317+
env_version = service_version_map.get(os.environ.get("AZURE_LIVE_TEST_SERVICE_VERSION","LATEST"))
318+
return kwargs.pop("service_version", env_version)
319+
320+
def create_storage_client(self, client, *args, **kwargs):
321+
kwargs["api_version"] = self._get_service_version(**kwargs)
322+
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
323+
return client(*args, **kwargs)
324+
325+
def create_storage_client_from_conn_str(self, client, *args, **kwargs):
326+
kwargs["api_version"] = self._get_service_version(**kwargs)
327+
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
328+
return client.from_connection_string(*args, **kwargs)
329+
313330

314331
def not_for_emulator(test):
315332
def skip_test_if_targeting_emulator(self):
316333
test(self)
317334
return skip_test_if_targeting_emulator
318335

319336

337+
class ApiVersionAssertPolicy(SansIOHTTPPolicy):
338+
"""
339+
Assert the ApiVersion is set properly on the response
340+
"""
341+
342+
def __init__(self, api_version):
343+
self.api_version = api_version
344+
345+
def on_request(self, request):
346+
assert request.http_request.headers['x-ms-version'] == self.api_version
347+
348+
320349
class RetryCounter(object):
321350
def __init__(self):
322351
self.count = 0

sdk/storage/azure-storage-queue/tests/test_queue_service_stats.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def override_response_body_with_live_status(response):
4949
@StorageAccountPreparer(name_prefix='pyacrstorage', sku='Standard_RAGRS', random_name_enabled=True)
5050
def test_queue_service_stats_f(self, resource_group, location, storage_account, storage_account_key):
5151
# Arrange
52-
qsc = QueueServiceClient(self.account_url(storage_account, "queue"), storage_account_key)
52+
qsc = self.create_storage_client(QueueServiceClient, self.account_url(storage_account, "queue"), storage_account_key)
5353

5454
# Act
5555
stats = qsc.get_service_stats(raw_response_hook=self.override_response_body_with_live_status)
@@ -60,11 +60,10 @@ def test_queue_service_stats_f(self, resource_group, location, storage_account,
6060
@StorageAccountPreparer(name_prefix='pyacrstorage', sku='Standard_RAGRS', random_name_enabled=True)
6161
def test_queue_service_stats_when_unavailable(self, resource_group, location, storage_account, storage_account_key):
6262
# Arrange
63-
qsc = QueueServiceClient(self.account_url(storage_account, "queue"), storage_account_key)
63+
qsc = self.create_storage_client(QueueServiceClient, self.account_url(storage_account, "queue"), storage_account_key)
6464

6565
# Act
66-
stats = qsc.get_service_stats(
67-
raw_response_hook=self.override_response_body_with_unavailable_status)
66+
stats = qsc.get_service_stats(raw_response_hook=self.override_response_body_with_unavailable_status)
6867

6968
# Assert
7069
self._assert_stats_unavailable(stats)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"displayNames": {
3+
"--disablecov": "",
4+
"false": "",
5+
"true": ""
6+
},
7+
"matrix": {
8+
"Agent": {
9+
"ubuntu-18.04": { "OSVmImage": "MMSUbuntu18.04", "Pool": "azsdk-pool-mms-ubuntu-1804-general" },
10+
"windows-2019": { "OSVmImage": "MMS2019", "Pool": "azsdk-pool-mms-win-2019-general" },
11+
"macOS-10.15": { "OSVmImage": "macOS-10.15", "Pool": "Azure Pipelines" }
12+
},
13+
"PythonVersion": [ "pypy3", "2.7", "3.6", "3.7", "3.8", "3.9" ],
14+
"CoverageArg": "--disablecov",
15+
"TestSamples": "false",
16+
"AZURE_LIVE_TEST_SERVICE_VERSION": [
17+
"V2019_02_02",
18+
"V2019_07_07",
19+
"V2019_12_12",
20+
"V2020_02_10",
21+
"V2020_04_08",
22+
"V2020_06_12",
23+
"V2020_08_04"
24+
]
25+
}
26+
}

sdk/storage/tests.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ stages:
2626
MatrixReplace:
2727
# Use dedicated storage pool in canadacentral with higher memory capacity
2828
- Pool=(.*)-general/$1-storage
29+
${{ if contains(variables['Build.DefinitionName'], 'tests-weekly') }}:
30+
MatrixConfigs:
31+
- Name: Storage_all_versions_live_test
32+
Path: sdk/storage/platform-matrix-all-versions.json
33+
Selection: sparse
34+
GenerateVMJobs: true
2935
EnvVars:
3036
STORAGE_ACCOUNT_NAME: $(python-storage-storage-account-name)
3137
STORAGE_ACCOUNT_KEY: $(python-storage-storage-account-key)
@@ -51,4 +57,4 @@ stages:
5157
AZURE_TENANT_ID: $(aad-azure-sdk-test-tenant-id)
5258
AZURE_SUBSCRIPTION_ID: $(azure-subscription-id)
5359
AZURE_CLIENT_SECRET: $(aad-azure-sdk-test-client-secret)
54-
AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id)
60+
AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id)

0 commit comments

Comments
 (0)