Aligning airlock processor unittests to use pytest (#3086)

* aligning airlock processor unittests to use pytest

* update changelog

* update version

* Update airlock_processor/tests/shared_code/test_blob_operations.py

Co-authored-by: Tamir Kamara <26870601+tamirkamara@users.noreply.github.com>

* Update airlock_processor/tests/test_status_change_queue_trigger.py

Co-authored-by: Tamir Kamara <26870601+tamirkamara@users.noreply.github.com>

* adding mock to the req dev file

* fix

Co-authored-by: Tamir Kamara <26870601+tamirkamara@users.noreply.github.com>
This commit is contained in:
Elad Iwanir 2023-01-18 10:44:10 +02:00 коммит произвёл GitHub
Родитель 76ea0efa7a
Коммит 44d3b91069
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 62 добавлений и 60 удалений

Просмотреть файл

@ -37,6 +37,7 @@ ENHANCEMENTS:
* Upgrade Guacamole dependencies ([#3053](https://github.com/microsoft/AzureTRE/pull/3053))
* Lint TRE cost tags per entity type (workspace, shared service, etc.) ([#3061](https://github.com/microsoft/AzureTRE/pull/3061))
* Validate required secrets have value ([#3073](https://github.com/microsoft/AzureTRE/pull/3073))
* Airlock processor unittests uses pytest ([#3026](https://github.com/microsoft/AzureTRE/pull/3026))
BUG FIXES:

Просмотреть файл

@ -1 +1 @@
__version__ = "0.4.12"
__version__ = "0.4.13"

Просмотреть файл

@ -1,2 +1,3 @@
# Dev requirements
pytest==7.2.0
mock==5.0.0

Просмотреть файл

@ -1,47 +1,49 @@
from collections import namedtuple
import json
from unittest import TestCase
from unittest.mock import MagicMock, patch
import pytest
from mock import MagicMock, patch
from shared_code.blob_operations import get_blob_info_from_topic_and_subject, get_blob_info_from_blob_url, copy_data, get_blob_url
from exceptions import TooManyFilesInRequestException, NoFilesInRequestException
TestBlob = namedtuple("Blob", "name")
def get_test_blob():
return namedtuple("Blob", "name")
class TestBlobOperations(TestCase):
class TestBlobOperations():
def test_get_blob_info_from_topic_and_subject(self):
topic = "/subscriptions/SUB_ID/resourceGroups/RG_NAME/providers/Microsoft.Storage/storageAccounts/ST_ACC_NAME"
subject = "/blobServices/default/containers/c144728c-3c69-4a58-afec-48c2ec8bfd45/blobs/BLOB"
storage_account_name, container_name, blob_name = get_blob_info_from_topic_and_subject(topic=topic, subject=subject)
self.assertEqual(storage_account_name, "ST_ACC_NAME")
self.assertEqual(container_name, "c144728c-3c69-4a58-afec-48c2ec8bfd45")
self.assertEqual(blob_name, "BLOB")
assert storage_account_name == "ST_ACC_NAME"
assert container_name == "c144728c-3c69-4a58-afec-48c2ec8bfd45"
assert blob_name == "BLOB"
def test_get_blob_info_from_url(self):
url = "https://stalimextest.blob.core.windows.net/c144728c-3c69-4a58-afec-48c2ec8bfd45/test_dataset.txt"
storage_account_name, container_name, blob_name = get_blob_info_from_blob_url(blob_url=url)
self.assertEqual(storage_account_name, "stalimextest")
self.assertEqual(container_name, "c144728c-3c69-4a58-afec-48c2ec8bfd45")
self.assertEqual(blob_name, "test_dataset.txt")
assert storage_account_name == "stalimextest"
assert container_name == "c144728c-3c69-4a58-afec-48c2ec8bfd45"
assert blob_name == "test_dataset.txt"
@patch("shared_code.blob_operations.BlobServiceClient")
def test_copy_data_fails_if_too_many_blobs_to_copy(self, mock_blob_service_client):
mock_blob_service_client().get_container_client().list_blobs = MagicMock(return_value=[TestBlob("a"), TestBlob("b")])
mock_blob_service_client().get_container_client().list_blobs = MagicMock(return_value=[get_test_blob()("a"), get_test_blob()("b")])
with self.assertRaises(TooManyFilesInRequestException):
with pytest.raises(TooManyFilesInRequestException):
copy_data("source_acc", "dest_acc", "req_id")
@patch("shared_code.blob_operations.BlobServiceClient")
def test_copy_data_fails_if_no_blobs_to_copy(self, mock_blob_service_client):
mock_blob_service_client().get_container_client().list_blobs = MagicMock(return_value=[])
with self.assertRaises(NoFilesInRequestException):
with pytest.raises(NoFilesInRequestException):
copy_data("source_acc", "dest_acc", "req_id")
@patch("shared_code.blob_operations.BlobServiceClient")
@ -69,7 +71,7 @@ class TestBlobOperations(TestCase):
# Any additional mocks for the copy_data method to work
mock_blob_service_client().get_user_delegation_key = MagicMock(return_value="key")
mock_blob_service_client().get_container_client().list_blobs = MagicMock(return_value=[TestBlob("a")])
mock_blob_service_client().get_container_client().list_blobs = MagicMock(return_value=[get_test_blob()("a")])
copy_data("source_acc", "dest_acc", "req_id")
@ -82,11 +84,11 @@ class TestBlobOperations(TestCase):
blob_name = "blob"
blob_url = get_blob_url(account_name, container_name, blob_name)
self.assertEqual(blob_url, f"https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}")
assert blob_url == f"https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}"
def test_get_blob_url_without_blob_name_should_return_container_url(self):
account_name = "account"
container_name = "container"
blob_url = get_blob_url(account_name, container_name)
self.assertEqual(blob_url, f"https://{account_name}.blob.core.windows.net/{container_name}/")
assert blob_url == f"https://{account_name}.blob.core.windows.net/{container_name}/"

Просмотреть файл

@ -1,10 +1,9 @@
from unittest import TestCase
from unittest.mock import MagicMock, patch
from mock import patch, MagicMock
from DataDeletionTrigger import delete_blob_and_container_if_last_blob
class TestDataDeletionTrigger(TestCase):
class TestDataDeletionTrigger():
@patch("DataDeletionTrigger.BlobServiceClient")
def test_delete_blob_and_container_if_last_blob_deletes_container(self, mock_blob_service_client):
blob_url = "https://stalimextest.blob.core.windows.net/c144728c-3c69-4a58-afec-48c2ec8bfd45/test_dataset.txt"

Просмотреть файл

@ -1,8 +1,7 @@
from json import JSONDecodeError
import os
import unittest
from unittest import mock
from unittest.mock import MagicMock, patch
import pytest
from mock import MagicMock, patch
from pydantic import ValidationError
from StatusChangedQueueTrigger import get_request_files, main, extract_properties, get_source_dest_for_copy, is_require_data_copy
@ -10,74 +9,74 @@ from azure.functions.servicebus import ServiceBusMessage
from shared_code import constants
class TestPropertiesExtraction(unittest.TestCase):
class TestPropertiesExtraction():
def test_extract_prop_valid_body_return_all_values(self):
message_body = "{ \"data\": { \"request_id\":\"123\",\"new_status\":\"456\" ,\"previous_status\":\"789\" , \"type\":\"101112\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
req_prop = extract_properties(message)
self.assertEqual(req_prop.request_id, "123")
self.assertEqual(req_prop.new_status, "456")
self.assertEqual(req_prop.previous_status, "789")
self.assertEqual(req_prop.type, "101112")
self.assertEqual(req_prop.workspace_id, "ws1")
assert req_prop.request_id == "123"
assert req_prop.new_status == "456"
assert req_prop.previous_status == "789"
assert req_prop.type == "101112"
assert req_prop.workspace_id == "ws1"
def test_extract_prop_missing_arg_throws(self):
message_body = "{ \"data\": { \"status\":\"456\" , \"type\":\"789\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
self.assertRaises(ValidationError, extract_properties, message)
pytest.raises(ValidationError, extract_properties, message)
message_body = "{ \"data\": { \"request_id\":\"123\", \"type\":\"789\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
self.assertRaises(ValidationError, extract_properties, message)
pytest.raises(ValidationError, extract_properties, message)
message_body = "{ \"data\": { \"request_id\":\"123\",\"status\":\"456\" , \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
self.assertRaises(ValidationError, extract_properties, message)
pytest.raises(ValidationError, extract_properties, message)
message_body = "{ \"data\": { \"request_id\":\"123\",\"status\":\"456\" , \"type\":\"789\" }}"
message = _mock_service_bus_message(body=message_body)
self.assertRaises(ValidationError, extract_properties, message)
pytest.raises(ValidationError, extract_properties, message)
def test_extract_prop_invalid_json_throws(self):
message_body = "Hi"
message = _mock_service_bus_message(body=message_body)
self.assertRaises(JSONDecodeError, extract_properties, message)
pytest.raises(JSONDecodeError, extract_properties, message)
class TestDataCopyProperties(unittest.TestCase):
class TestDataCopyProperties():
def test_only_specific_status_are_triggering_copy(self):
self.assertEqual(is_require_data_copy("Mitzi"), False)
self.assertEqual(is_require_data_copy(""), False)
self.assertEqual(is_require_data_copy("submit"), False)
self.assertEqual(is_require_data_copy("approved"), False)
self.assertEqual(is_require_data_copy("REJected"), False)
self.assertEqual(is_require_data_copy("blocked"), False)
assert not is_require_data_copy("Mitzi")
assert not is_require_data_copy("")
assert not is_require_data_copy("submit")
assert not is_require_data_copy("approved")
assert not is_require_data_copy("REJected")
assert not is_require_data_copy("blocked")
# Testing all values that should return true
self.assertEqual(is_require_data_copy("submITted"), True)
self.assertEqual(is_require_data_copy("submitted"), True)
self.assertEqual(is_require_data_copy("approval_in_progress"), True)
self.assertEqual(is_require_data_copy("rejection_in_progress"), True)
self.assertEqual(is_require_data_copy("blocking_in_progress"), True)
assert is_require_data_copy("submITted")
assert is_require_data_copy("submitted")
assert is_require_data_copy("approval_in_progress")
assert is_require_data_copy("rejection_in_progress")
assert is_require_data_copy("blocking_in_progress")
def test_wrong_status_raises_when_getting_storage_account_properties(self):
self.assertRaises(Exception, get_source_dest_for_copy, "Miaow", "import")
pytest.raises(Exception, get_source_dest_for_copy, "Miaow", "import")
def test_wrong_type_raises_when_getting_storage_account_properties(self):
self.assertRaises(Exception, get_source_dest_for_copy, "accepted", "somethingelse")
pytest.raises(Exception, get_source_dest_for_copy, "accepted", "somethingelse")
class TestFileEnumeration(unittest.TestCase):
class TestFileEnumeration():
@patch("StatusChangedQueueTrigger.set_output_event_to_report_request_files")
@patch("StatusChangedQueueTrigger.get_request_files")
@patch("StatusChangedQueueTrigger.is_require_data_copy", return_value=False)
@mock.patch.dict(os.environ, {"TRE_ID": "tre-id"}, clear=True)
@patch.dict(os.environ, {"TRE_ID": "tre-id"}, clear=True)
def test_get_request_files_should_be_called_on_submit_stage(self, _, mock_get_request_files, mock_set_output_event_to_report_request_files):
message_body = "{ \"data\": { \"request_id\":\"123\",\"new_status\":\"submitted\" ,\"previous_status\":\"draft\" , \"type\":\"export\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
main(msg=message, stepResultEvent=MagicMock(), dataDeletionEvent=MagicMock())
self.assertTrue(mock_get_request_files.called)
self.assertTrue(mock_set_output_event_to_report_request_files.called)
assert mock_get_request_files.called
assert mock_set_output_event_to_report_request_files.called
@patch("StatusChangedQueueTrigger.set_output_event_to_report_failure")
@patch("StatusChangedQueueTrigger.get_request_files")
@ -86,8 +85,8 @@ class TestFileEnumeration(unittest.TestCase):
message_body = "{ \"data\": { \"request_id\":\"123\",\"new_status\":\"fake-status\" ,\"previous_status\":\"None\" , \"type\":\"export\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
main(msg=message, stepResultEvent=MagicMock(), dataDeletionEvent=MagicMock())
self.assertFalse(mock_get_request_files.called)
self.assertFalse(mock_set_output_event_to_report_failure.called)
assert not mock_get_request_files.called
assert not mock_set_output_event_to_report_failure.called
@patch("StatusChangedQueueTrigger.set_output_event_to_report_failure")
@patch("StatusChangedQueueTrigger.get_request_files")
@ -96,11 +95,11 @@ class TestFileEnumeration(unittest.TestCase):
message_body = "{ \"data\": { \"request_id\":\"123\",\"new_status\":\"submitted\" ,\"previous_status\":\"draft\" , \"type\":\"export\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
main(msg=message, stepResultEvent=MagicMock(), dataDeletionEvent=MagicMock())
self.assertTrue(mock_get_request_files.called)
self.assertTrue(mock_set_output_event_to_report_failure.called)
assert mock_get_request_files.called
assert mock_set_output_event_to_report_failure.called
@patch("StatusChangedQueueTrigger.blob_operations.get_request_files")
@mock.patch.dict(os.environ, {"TRE_ID": "tre-id"}, clear=True)
@patch.dict(os.environ, {"TRE_ID": "tre-id"}, clear=True)
def test_get_request_files_called_with_correct_storage_account(self, mock_get_request_files):
source_storage_account_for_submitted_stage = constants.STORAGE_ACCOUNT_NAME_EXPORT_INTERNAL + 'ws1'
message_body = "{ \"data\": { \"request_id\":\"123\",\"new_status\":\"submitted\" ,\"previous_status\":\"draft\" , \"type\":\"export\", \"workspace_id\":\"ws1\" }}"
@ -110,14 +109,14 @@ class TestFileEnumeration(unittest.TestCase):
mock_get_request_files.assert_called_with(account_name=source_storage_account_for_submitted_stage, request_id=request_properties.request_id)
class TestFilesDeletion(unittest.TestCase):
class TestFilesDeletion():
@patch("StatusChangedQueueTrigger.set_output_event_to_trigger_container_deletion")
@mock.patch.dict(os.environ, {"TRE_ID": "tre-id"}, clear=True)
@patch.dict(os.environ, {"TRE_ID": "tre-id"}, clear=True)
def test_delete_request_files_should_be_called_on_cancel_stage(self, mock_set_output_event_to_trigger_container_deletion):
message_body = "{ \"data\": { \"request_id\":\"123\",\"new_status\":\"cancelled\" ,\"previous_status\":\"draft\" , \"type\":\"export\", \"workspace_id\":\"ws1\" }}"
message = _mock_service_bus_message(body=message_body)
main(msg=message, stepResultEvent=MagicMock(), dataDeletionEvent=MagicMock())
self.assertTrue(mock_set_output_event_to_trigger_container_deletion.called)
assert mock_set_output_event_to_trigger_container_deletion.called
def _mock_service_bus_message(body: str):