Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Storage][Test] Test multiple service versions #19039

Merged
merged 10 commits into from
Jun 9, 2021
42 changes: 42 additions & 0 deletions sdk/storage/azure-storage-blob/tests/_shared/service_versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from datetime import datetime
from enum import Enum
import os


class ServiceVersion(str, Enum):

V2019_02_02 = "2019-02-02"
V2019_07_07 = "2019-07-07"
V2019_10_10 = "2019-10-10"
V2019_12_12 = "2019-12-12"
V2020_02_10 = "2020-02-10"
V2020_04_08 = "2020-04-08"
V2020_06_12 = "2020-06-12"
V2020_08_04 = "2020-08-04"


service_version_map = {
"V2019_02_02": ServiceVersion.V2019_02_02,
"V2019_07_07": ServiceVersion.V2019_07_07,
"V2019_10_10": ServiceVersion.V2019_10_10,
"V2019_12_12": ServiceVersion.V2019_12_12,
"V2020_02_10": ServiceVersion.V2020_02_10,
"V2020_04_08": ServiceVersion.V2020_04_08,
"V2020_06_12": ServiceVersion.V2020_06_12,
"V2020_08_04": ServiceVersion.V2020_08_04,
"LATEST": ServiceVersion.V2020_08_04,
"LATEST_PLUS_1": ServiceVersion.V2020_06_12
}


def is_version_before(test_version):
""" Return True if the current version is after a given one or if the
service version is not set.
"""
current_version = service_version_map.get(os.environ.get("AZURE_LIVE_TEST_SERVICE_VERSION"))
if not current_version:
return True
current_version_data = datetime.strptime(current_version, "%Y-%m-%d")
test_version_minimum = datetime.strptime(test_version, "%Y-%m-%d")
ret = current_version_data < test_version_minimum
return ret
31 changes: 30 additions & 1 deletion sdk/storage/azure-storage-blob/tests/_shared/testcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import zlib
import math
import sys
import string
import os
import random
import re
import logging
Expand All @@ -34,6 +34,7 @@
except ImportError:
from io import StringIO

from azure.core.pipeline.policies import SansIOHTTPPolicy
from azure.core.exceptions import ResourceNotFoundError, HttpResponseError
from azure.core.credentials import AccessToken
from azure.storage.blob import generate_account_sas, AccountSasPermissions, ResourceTypes
Expand All @@ -50,6 +51,8 @@
except ImportError:
from devtools_testutils import mgmt_settings_fake as settings

from .service_versions import service_version_map

import pytest


Expand Down Expand Up @@ -310,6 +313,32 @@ def generate_sas_token(self):
def generate_fake_token(self):
return FakeTokenCredential()

def _get_service_version(self, **kwargs):
env_version = service_version_map.get(os.environ.get("AZURE_LIVE_TEST_SERVICE_VERSION","LATEST"))
return kwargs.pop("service_version", env_version)

def create_storage_client(self, client, *args, **kwargs):
kwargs["api_version"] = self._get_service_version(**kwargs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in nightly pipeline we'd like clients to pick the default, i.e. env variable is empty.
does this code achieve this by leaving "api_version" kwarg empty or we need some "if" here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the environment variable is empty, it will default to LATEST_SERVICE_VERSION

kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
return client(*args, **kwargs)

def create_storage_client_from_conn_str(self, client, *args, **kwargs):
kwargs["api_version"] = self._get_service_version(**kwargs)
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
return client.from_connection_string(*args, **kwargs)


class ApiVersionAssertPolicy(SansIOHTTPPolicy):
"""
Assert the ApiVersion is set properly on the response
"""

def __init__(self, api_version):
self.api_version = api_version

def on_request(self, request):
assert request.http_request.headers['x-ms-version'] == self.api_version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this throw if env variable is empty? , we should either handle it here or not inject policy if there's no service version provided extrenally.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, if the env variable is empty it will default to LATEST_SERVICE_VERSION



def not_for_emulator(test):
def skip_test_if_targeting_emulator(self):
Expand Down
19 changes: 18 additions & 1 deletion sdk/storage/azure-storage-blob/tests/test_blob_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
BlobBlock, generate_account_sas, ResourceTypes, AccountSasPermissions, generate_container_sas,
ContainerSasPermissions, BlobClient, generate_blob_sas, BlobSasPermissions)

from _shared.service_versions import is_version_before, ServiceVersion

#------------------------------------------------------------------------------

TEST_CONTAINER_PREFIX = 'container'
Expand All @@ -34,7 +36,7 @@
class StorageBlobTagsTest(StorageTestCase):

def _setup(self, storage_account, key):
self.bsc = BlobServiceClient(self.account_url(storage_account, "blob"), credential=key)
self.bsc = self.create_storage_client(BlobServiceClient, self.account_url(storage_account, "blob"), credential=key)
self.container_name = self.get_resource_name("container")
if self.is_live:
container = self.bsc.get_container_client(self.container_name)
Expand Down Expand Up @@ -90,6 +92,7 @@ def _create_container(self, prefix="container"):

#-- test cases for blob tags ----------------------------------------------

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

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

blob_client.delete_blob(lease=lease)

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

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

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

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

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

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

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

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

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

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

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

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

@pytest.mark.skipif(is_version_before(ServiceVersion.V2019_12_12), reason="SV too low")
@pytest.mark.live_test_only
@GlobalResourceGroupPreparer()
@StorageAccountPreparer(random_name_enabled=True, location="canadacentral", name_prefix='pytagstorage')
Expand Down
27 changes: 27 additions & 0 deletions sdk/storage/azure-storage-queue/tests/_shared/service_versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from enum import Enum


class ServiceVersion(str, Enum):

V2019_02_02 = "2019-02-02"
V2019_07_07 = "2019-07-07"
V2019_10_10 = "2019-10-10"
V2019_12_12 = "2019-12-12"
V2020_02_10 = "2020-02-10"
V2020_04_08 = "2020-04-08"
V2020_06_12 = "2020-06-12"
V2020_08_04 = "2020-08-04"


service_version_map = {
"V2019_02_02": ServiceVersion.V2019_02_02,
"V2019_07_07": ServiceVersion.V2019_07_07,
"V2019_10_10": ServiceVersion.V2019_10_10,
"V2019_12_12": ServiceVersion.V2019_12_12,
"V2020_02_10": ServiceVersion.V2020_02_10,
"V2020_04_08": ServiceVersion.V2020_04_08,
"V2020_06_12": ServiceVersion.V2020_06_12,
"V2020_08_04": ServiceVersion.V2020_08_04,
"LATEST": ServiceVersion.V2020_08_04,
"LATEST_PLUS_1": ServiceVersion.V2020_06_12
}
29 changes: 29 additions & 0 deletions sdk/storage/azure-storage-queue/tests/_shared/testcase.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
except ImportError:
from io import StringIO

from azure.core.pipeline.policies import SansIOHTTPPolicy
from azure.core.exceptions import ResourceNotFoundError, HttpResponseError
from azure.core.credentials import AccessToken
from azure.storage.queue import generate_account_sas, AccountSasPermissions, ResourceTypes
Expand All @@ -52,6 +53,8 @@

import pytest

from .service_versions import service_version_map


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

def _get_service_version(self, **kwargs):
env_version = service_version_map.get(os.environ.get("AZURE_LIVE_TEST_SERVICE_VERSION","LATEST"))
return kwargs.pop("service_version", env_version)

def create_storage_client(self, client, *args, **kwargs):
kwargs["api_version"] = self._get_service_version(**kwargs)
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
return client(*args, **kwargs)

def create_storage_client_from_conn_str(self, client, *args, **kwargs):
kwargs["api_version"] = self._get_service_version(**kwargs)
kwargs["_additional_pipeline_policies"] = [ApiVersionAssertPolicy(kwargs["api_version"])]
return client.from_connection_string(*args, **kwargs)


def not_for_emulator(test):
def skip_test_if_targeting_emulator(self):
test(self)
return skip_test_if_targeting_emulator


class ApiVersionAssertPolicy(SansIOHTTPPolicy):
"""
Assert the ApiVersion is set properly on the response
"""

def __init__(self, api_version):
self.api_version = api_version

def on_request(self, request):
assert request.http_request.headers['x-ms-version'] == self.api_version


class RetryCounter(object):
def __init__(self):
self.count = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def override_response_body_with_live_status(response):
@StorageAccountPreparer(name_prefix='pyacrstorage', sku='Standard_RAGRS', random_name_enabled=True)
def test_queue_service_stats_f(self, resource_group, location, storage_account, storage_account_key):
# Arrange
qsc = QueueServiceClient(self.account_url(storage_account, "queue"), storage_account_key)
qsc = self.create_storage_client(QueueServiceClient, self.account_url(storage_account, "queue"), storage_account_key)

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

# Act
stats = qsc.get_service_stats(
raw_response_hook=self.override_response_body_with_unavailable_status)
stats = qsc.get_service_stats(raw_response_hook=self.override_response_body_with_unavailable_status)

# Assert
self._assert_stats_unavailable(stats)
Expand Down
26 changes: 26 additions & 0 deletions sdk/storage/platform-matrix-all-versions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"displayNames": {
"--disablecov": "",
"false": "",
"true": ""
},
"matrix": {
"Agent": {
"ubuntu-18.04": { "OSVmImage": "MMSUbuntu18.04", "Pool": "azsdk-pool-mms-ubuntu-1804-general" },
"windows-2019": { "OSVmImage": "MMS2019", "Pool": "azsdk-pool-mms-win-2019-general" },
"macOS-10.15": { "OSVmImage": "macOS-10.15", "Pool": "Azure Pipelines" }
},
"PythonVersion": [ "pypy3", "2.7", "3.6", "3.7", "3.8", "3.9" ],
"CoverageArg": "--disablecov",
"TestSamples": "false",
"AZURE_LIVE_TEST_SERVICE_VERSION": [
"V2019_02_02",
"V2019_07_07",
"V2019_12_12",
"V2020_02_10",
"V2020_04_08",
"V2020_06_12",
"V2020_08_04"
]
}
}
8 changes: 7 additions & 1 deletion sdk/storage/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ stages:
MatrixReplace:
# Use dedicated storage pool in canadacentral with higher memory capacity
- Pool=(.*)-general/$1-storage
${{ if contains(variables['Build.DefinitionName'], 'tests-weekly') }}:
MatrixConfigs:
- Name: Storage_all_versions_live_test
Path: sdk/storage/platform-matrix-all-versions.json
Selection: sparse
GenerateVMJobs: true
EnvVars:
STORAGE_ACCOUNT_NAME: $(python-storage-storage-account-name)
STORAGE_ACCOUNT_KEY: $(python-storage-storage-account-key)
Expand All @@ -51,4 +57,4 @@ stages:
AZURE_TENANT_ID: $(aad-azure-sdk-test-tenant-id)
AZURE_SUBSCRIPTION_ID: $(azure-subscription-id)
AZURE_CLIENT_SECRET: $(aad-azure-sdk-test-client-secret)
AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id)
AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id)