From b247c53cd2f539ae936a612d61824ce3993f9d55 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 4 Sep 2019 10:18:39 -0400 Subject: [PATCH 01/10] id helper --- atst/domain/csp/cloud.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index b517699c..bce870cc 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -116,21 +116,21 @@ class CloudProviderInterface: class MockCloudProvider(CloudProviderInterface): def create_environment(self, auth_credentials, user, environment): - return uuid4().hex + return self._id() def create_atat_admin_user(self, auth_credentials, csp_environment_id): - return {"id": uuid4().hex, "credentials": {}} + return {"id": self._id(), "credentials": {}} def create_environment_baseline(self, auth_credentials, csp_environment_id): return { - CSPRole.BASIC_ACCESS: uuid4().hex, - CSPRole.NETWORK_ADMIN: uuid4().hex, - CSPRole.BUSINESS_READ: uuid4().hex, - CSPRole.TECHNICAL_READ: uuid4().hex, + CSPRole.BASIC_ACCESS: self._id(), + CSPRole.NETWORK_ADMIN: self._id(), + CSPRole.BUSINESS_READ: self._id(), + CSPRole.TECHNICAL_READ: self._id(), } def create_or_update_user(self, auth_credentials, user_info, csp_role_id): - return {"id": uuid4().hex} + return {"id": self._id()} def suspend_user(self, auth_credentials, csp_user_id): pass @@ -145,3 +145,6 @@ class MockCloudProvider(CloudProviderInterface): """Returns the login url for a given environment """ return "https://www.mycloud.com/my-env-login" + + def _id(self): + return uuid4().hex From 523f41a75d6532478ae1f32412c8d76e324cd207 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 4 Sep 2019 10:45:56 -0400 Subject: [PATCH 02/10] Delay and network errors --- atst/domain/csp/cloud.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index bce870cc..d5498892 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -115,7 +115,24 @@ class CloudProviderInterface: class MockCloudProvider(CloudProviderInterface): + AUTH_EXCEPTION = ValueError("Could not authenticate.") + NETWORK_EXCEPTION = ValueError("Network failure.") + + NETWORK_FAILURE_PCT = 12 + + def __init__(self, with_delay=True, with_failure=True): + from time import sleep + import random + + self._with_delay = with_delay + self._with_failure = with_failure + self._sleep = sleep + self._random = random + def create_environment(self, auth_credentials, user, environment): + self._delay(1, 5) + self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + return self._id() def create_atat_admin_user(self, auth_credentials, csp_environment_id): @@ -148,3 +165,20 @@ class MockCloudProvider(CloudProviderInterface): def _id(self): return uuid4().hex + + def _delay(self, min_secs, max_secs): + if self._with_delay: + duration = self._random.randrange(min_secs, max_secs) + self._sleep(duration) + + def _maybe_throw(self, pct, exc): + if self._with_failure and self._random.randrange(0, 100) < pct: + raise exc + + def _auth_credentials(self): + return {"username": "mock-cloud", "pass": "shh"} + + def _authorize(self, credentials): + if credentials != _auth_credentials(): + # TODO: Real exception + raise self.AUTH_EXCEPTION From 63e6671f7ffdd57ce57d5c4ea0f515d7ee602f1f Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 4 Sep 2019 10:46:13 -0400 Subject: [PATCH 03/10] Add test for mock CSP (probably temporary) --- tests/domain/test_mock_csp.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/domain/test_mock_csp.py diff --git a/tests/domain/test_mock_csp.py b/tests/domain/test_mock_csp.py new file mode 100644 index 00000000..52bb461a --- /dev/null +++ b/tests/domain/test_mock_csp.py @@ -0,0 +1,13 @@ +import pytest + +from atst.domain.csp import MockCloudProvider + + +@pytest.fixture +def mock_csp(): + return MockCloudProvider(with_delay=False, with_failure=False) + + +def test_create_environment(mock_csp: MockCloudProvider): + environment_id = mock_csp.create_environment({}, {}, {}) + assert isinstance(environment_id, str) From f757e86eb3d881bc1edf30cb2a312940e6e6ddc3 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 4 Sep 2019 10:50:56 -0400 Subject: [PATCH 04/10] Update TODOs --- atst/domain/csp/cloud.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index d5498892..b0b46c37 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -115,6 +115,8 @@ class CloudProviderInterface: class MockCloudProvider(CloudProviderInterface): + + # TODO: All of these constants AUTH_EXCEPTION = ValueError("Could not authenticate.") NETWORK_EXCEPTION = ValueError("Network failure.") @@ -180,5 +182,4 @@ class MockCloudProvider(CloudProviderInterface): def _authorize(self, credentials): if credentials != _auth_credentials(): - # TODO: Real exception raise self.AUTH_EXCEPTION From 25bedb816dfc2527f85eea19e3eba3fab5dee93d Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 4 Sep 2019 11:25:09 -0400 Subject: [PATCH 05/10] Auth create_environment --- atst/domain/csp/cloud.py | 15 ++++++++++++--- tests/domain/test_mock_csp.py | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index b0b46c37..7b67e7d3 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -7,6 +7,10 @@ from atst.models.environment import Environment from atst.models.environment_role import EnvironmentRole +class GeneralCSPException(Exception): + pass + + class CloudProviderInterface: def create_environment( self, auth_credentials: Dict, user: User, environment: Environment @@ -117,10 +121,11 @@ class CloudProviderInterface: class MockCloudProvider(CloudProviderInterface): # TODO: All of these constants - AUTH_EXCEPTION = ValueError("Could not authenticate.") - NETWORK_EXCEPTION = ValueError("Network failure.") + AUTH_EXCEPTION = GeneralCSPException("Authentication failure.") + NETWORK_EXCEPTION = GeneralCSPException("Network failure.") NETWORK_FAILURE_PCT = 12 + ENV_CREATE_FAILURE_PCT = 12 def __init__(self, with_delay=True, with_failure=True): from time import sleep @@ -132,8 +137,12 @@ class MockCloudProvider(CloudProviderInterface): self._random = random def create_environment(self, auth_credentials, user, environment): + self._delay(1, 5) + self._authorize(auth_credentials) + self._delay(1, 5) self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_throw(self.ENV_CREATE_FAILURE_PCT, GeneralCSPException("Could not create environment.")) return self._id() @@ -181,5 +190,5 @@ class MockCloudProvider(CloudProviderInterface): return {"username": "mock-cloud", "pass": "shh"} def _authorize(self, credentials): - if credentials != _auth_credentials(): + if credentials != self._auth_credentials(): raise self.AUTH_EXCEPTION diff --git a/tests/domain/test_mock_csp.py b/tests/domain/test_mock_csp.py index 52bb461a..a16b347f 100644 --- a/tests/domain/test_mock_csp.py +++ b/tests/domain/test_mock_csp.py @@ -9,5 +9,6 @@ def mock_csp(): def test_create_environment(mock_csp: MockCloudProvider): - environment_id = mock_csp.create_environment({}, {}, {}) + credentials = mock_csp._auth_credentials() + environment_id = mock_csp.create_environment(credentials, {}, {}) assert isinstance(environment_id, str) From 62795561a86a629bc6bb002f1a02920bc9e67c7e Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 4 Sep 2019 17:10:49 -0400 Subject: [PATCH 06/10] All the methods --- atst/domain/csp/cloud.py | 49 ++++++++++++++++++++++++++++++----- tests/domain/test_mock_csp.py | 28 ++++++++++++++++++-- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 7b67e7d3..ea512b08 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -124,8 +124,9 @@ class MockCloudProvider(CloudProviderInterface): AUTH_EXCEPTION = GeneralCSPException("Authentication failure.") NETWORK_EXCEPTION = GeneralCSPException("Network failure.") - NETWORK_FAILURE_PCT = 12 + NETWORK_FAILURE_PCT = 7 ENV_CREATE_FAILURE_PCT = 12 + ATAT_ADMIN_CREATE_FAILURE_PCT = 12 def __init__(self, with_delay=True, with_failure=True): from time import sleep @@ -137,19 +138,39 @@ class MockCloudProvider(CloudProviderInterface): self._random = random def create_environment(self, auth_credentials, user, environment): - self._delay(1, 5) self._authorize(auth_credentials) self._delay(1, 5) self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) - self._maybe_throw(self.ENV_CREATE_FAILURE_PCT, GeneralCSPException("Could not create environment.")) + self._maybe_throw( + self.ENV_CREATE_FAILURE_PCT, + GeneralCSPException("Could not create environment."), + ) return self._id() def create_atat_admin_user(self, auth_credentials, csp_environment_id): + self._authorize(auth_credentials) + + self._delay(1, 5) + self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_throw( + self.ATAT_ADMIN_CREATE_FAILURE_PCT, + GeneralCSPException("Could not create admin user."), + ) + return {"id": self._id(), "credentials": {}} def create_environment_baseline(self, auth_credentials, csp_environment_id): + self._authorize(auth_credentials) + + self._delay(1, 5) + self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_throw( + self.ATAT_ADMIN_CREATE_FAILURE_PCT, + GeneralCSPException("Could not create environment baseline."), + ) + return { CSPRole.BASIC_ACCESS: self._id(), CSPRole.NETWORK_ADMIN: self._id(), @@ -158,13 +179,22 @@ class MockCloudProvider(CloudProviderInterface): } def create_or_update_user(self, auth_credentials, user_info, csp_role_id): + self._authorize(auth_credentials) + + self._delay(1, 5) + self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_throw( + self.ATAT_ADMIN_CREATE_FAILURE_PCT, + GeneralCSPException("Could not create user."), + ) + return {"id": self._id()} def suspend_user(self, auth_credentials, csp_user_id): - pass + return self._maybe(12) def delete_user(self, auth_credentials, csp_user_id): - pass + return self._maybe(12) def get_calculator_url(self): return "https://www.rackspace.com/en-us/calculator" @@ -182,13 +212,18 @@ class MockCloudProvider(CloudProviderInterface): duration = self._random.randrange(min_secs, max_secs) self._sleep(duration) + def _maybe(self, pct): + return not self._with_failure or self._random.randrange(0, 100) < pct + def _maybe_throw(self, pct, exc): - if self._with_failure and self._random.randrange(0, 100) < pct: + if self._with_failure and self._maybe(pct): raise exc + @property def _auth_credentials(self): return {"username": "mock-cloud", "pass": "shh"} def _authorize(self, credentials): - if credentials != self._auth_credentials(): + self._delay(1, 5) + if credentials != self._auth_credentials: raise self.AUTH_EXCEPTION diff --git a/tests/domain/test_mock_csp.py b/tests/domain/test_mock_csp.py index a16b347f..5dd063c8 100644 --- a/tests/domain/test_mock_csp.py +++ b/tests/domain/test_mock_csp.py @@ -2,6 +2,7 @@ import pytest from atst.domain.csp import MockCloudProvider +CREDENTIALS = MockCloudProvider()._auth_credentials @pytest.fixture def mock_csp(): @@ -9,6 +10,29 @@ def mock_csp(): def test_create_environment(mock_csp: MockCloudProvider): - credentials = mock_csp._auth_credentials() - environment_id = mock_csp.create_environment(credentials, {}, {}) + environment_id = mock_csp.create_environment(CREDENTIALS, {}, {}) assert isinstance(environment_id, str) + + +def test_create_admin_user(mock_csp: MockCloudProvider): + admin_user = mock_csp.create_atat_admin_user(CREDENTIALS, "env_id") + assert isinstance(admin_user["id"], str) + assert isinstance(admin_user["credentials"], dict) + + +def test_create_environment_baseline(mock_csp: MockCloudProvider): + baseline = mock_csp.create_atat_admin_user(CREDENTIALS, "env_id") + assert isinstance(baseline, dict) + + +def test_create_or_update_user(mock_csp: MockCloudProvider): + user_dict = mock_csp.create_or_update_user(CREDENTIALS, {}, "csp_role_id") + assert isinstance(user_dict["id"], str) + + +def test_suspend_user(mock_csp: MockCloudProvider): + assert mock_csp.suspend_user(CREDENTIALS, "csp_user_id") + + +def test_delete_user(mock_csp: MockCloudProvider): + assert mock_csp.delete_user(CREDENTIALS, "csp_user_id") From 43d5be4e19e7529dd63afae07286e64b73285ced Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 5 Sep 2019 09:48:40 -0400 Subject: [PATCH 07/10] Add network failures to suspend / delete user --- atst/domain/csp/cloud.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index ea512b08..610265c7 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -191,9 +191,11 @@ class MockCloudProvider(CloudProviderInterface): return {"id": self._id()} def suspend_user(self, auth_credentials, csp_user_id): + self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) return self._maybe(12) def delete_user(self, auth_credentials, csp_user_id): + self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) return self._maybe(12) def get_calculator_url(self): From 8347e4e38772a0df38b2b691e252f2e0d590643b Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 5 Sep 2019 09:52:23 -0400 Subject: [PATCH 08/10] Formatting --- tests/domain/test_mock_csp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/domain/test_mock_csp.py b/tests/domain/test_mock_csp.py index 5dd063c8..927bf304 100644 --- a/tests/domain/test_mock_csp.py +++ b/tests/domain/test_mock_csp.py @@ -4,6 +4,7 @@ from atst.domain.csp import MockCloudProvider CREDENTIALS = MockCloudProvider()._auth_credentials + @pytest.fixture def mock_csp(): return MockCloudProvider(with_delay=False, with_failure=False) From fd65a3a972a9a7c4cd52aa6c387f92bcf65275da Mon Sep 17 00:00:00 2001 From: richard-dds Date: Thu, 5 Sep 2019 09:58:56 -0400 Subject: [PATCH 09/10] Rename "throw" to "raise" --- atst/domain/csp/cloud.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 610265c7..9a1f2258 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -141,8 +141,8 @@ class MockCloudProvider(CloudProviderInterface): self._authorize(auth_credentials) self._delay(1, 5) - self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) - self._maybe_throw( + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise( self.ENV_CREATE_FAILURE_PCT, GeneralCSPException("Could not create environment."), ) @@ -153,8 +153,8 @@ class MockCloudProvider(CloudProviderInterface): self._authorize(auth_credentials) self._delay(1, 5) - self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) - self._maybe_throw( + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise( self.ATAT_ADMIN_CREATE_FAILURE_PCT, GeneralCSPException("Could not create admin user."), ) @@ -165,8 +165,8 @@ class MockCloudProvider(CloudProviderInterface): self._authorize(auth_credentials) self._delay(1, 5) - self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) - self._maybe_throw( + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise( self.ATAT_ADMIN_CREATE_FAILURE_PCT, GeneralCSPException("Could not create environment baseline."), ) @@ -182,8 +182,8 @@ class MockCloudProvider(CloudProviderInterface): self._authorize(auth_credentials) self._delay(1, 5) - self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) - self._maybe_throw( + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise( self.ATAT_ADMIN_CREATE_FAILURE_PCT, GeneralCSPException("Could not create user."), ) @@ -191,11 +191,11 @@ class MockCloudProvider(CloudProviderInterface): return {"id": self._id()} def suspend_user(self, auth_credentials, csp_user_id): - self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) return self._maybe(12) def delete_user(self, auth_credentials, csp_user_id): - self._maybe_throw(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) + self._maybe_raise(self.NETWORK_FAILURE_PCT, self.NETWORK_EXCEPTION) return self._maybe(12) def get_calculator_url(self): @@ -217,7 +217,7 @@ class MockCloudProvider(CloudProviderInterface): def _maybe(self, pct): return not self._with_failure or self._random.randrange(0, 100) < pct - def _maybe_throw(self, pct, exc): + def _maybe_raise(self, pct, exc): if self._with_failure and self._maybe(pct): raise exc From 6c0420d6c5e17fab36b15adf8970b760aaaac3f3 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 9 Sep 2019 10:45:38 -0400 Subject: [PATCH 10/10] Read config to determine mock CSP type --- atst/domain/csp/__init__.py | 12 ++++++++---- atst/domain/csp/cloud.py | 18 ++++++++++++------ config/test.ini | 1 + tests/domain/test_mock_csp.py | 4 ++-- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/atst/domain/csp/__init__.py b/atst/domain/csp/__init__.py index 1e288928..8c460ea1 100644 --- a/atst/domain/csp/__init__.py +++ b/atst/domain/csp/__init__.py @@ -4,22 +4,24 @@ from .reports import MockReportingProvider class MockCSP: - def __init__(self, app): - self.cloud = MockCloudProvider() + def __init__(self, app, test_mode=False): + self.cloud = MockCloudProvider( + app.config, with_delay=(not test_mode), with_failure=(not test_mode) + ) self.files = MockUploader(app) self.reports = MockReportingProvider() class AzureCSP: def __init__(self, app): - self.cloud = MockCloudProvider() + self.cloud = MockCloudProvider(app.config) self.files = AzureUploader(app.config) self.reports = MockReportingProvider() class AwsCSP: def __init__(self, app): - self.cloud = MockCloudProvider() + self.cloud = MockCloudProvider(app.config) self.files = AwsUploader(app.config) self.reports = MockReportingProvider() @@ -29,5 +31,7 @@ def make_csp_provider(app, csp=None): app.csp = AwsCSP(app) elif csp == "azure": app.csp = AzureCSP(app) + elif csp == "mock-test": + app.csp = MockCSP(app, test_mode=True) else: app.csp = MockCSP(app) diff --git a/atst/domain/csp/cloud.py b/atst/domain/csp/cloud.py index 9a1f2258..5f8689c1 100644 --- a/atst/domain/csp/cloud.py +++ b/atst/domain/csp/cloud.py @@ -12,6 +12,9 @@ class GeneralCSPException(Exception): class CloudProviderInterface: + def root_creds() -> Dict: + raise NotImplementedError() + def create_environment( self, auth_credentials: Dict, user: User, environment: Environment ) -> str: @@ -128,7 +131,7 @@ class MockCloudProvider(CloudProviderInterface): ENV_CREATE_FAILURE_PCT = 12 ATAT_ADMIN_CREATE_FAILURE_PCT = 12 - def __init__(self, with_delay=True, with_failure=True): + def __init__(self, config, with_delay=True, with_failure=True): from time import sleep import random @@ -137,6 +140,9 @@ class MockCloudProvider(CloudProviderInterface): self._sleep = sleep self._random = random + def root_creds(self): + return self._auth_credentials + def create_environment(self, auth_credentials, user, environment): self._authorize(auth_credentials) @@ -159,7 +165,7 @@ class MockCloudProvider(CloudProviderInterface): GeneralCSPException("Could not create admin user."), ) - return {"id": self._id(), "credentials": {}} + return {"id": self._id(), "credentials": self._auth_credentials} def create_environment_baseline(self, auth_credentials, csp_environment_id): self._authorize(auth_credentials) @@ -172,10 +178,10 @@ class MockCloudProvider(CloudProviderInterface): ) return { - CSPRole.BASIC_ACCESS: self._id(), - CSPRole.NETWORK_ADMIN: self._id(), - CSPRole.BUSINESS_READ: self._id(), - CSPRole.TECHNICAL_READ: self._id(), + CSPRole.BASIC_ACCESS.value: self._id(), + CSPRole.NETWORK_ADMIN.value: self._id(), + CSPRole.BUSINESS_READ.value: self._id(), + CSPRole.TECHNICAL_READ.value: self._id(), } def create_or_update_user(self, auth_credentials, user_info, csp_role_id): diff --git a/config/test.ini b/config/test.ini index c323f599..37a9e629 100644 --- a/config/test.ini +++ b/config/test.ini @@ -6,3 +6,4 @@ CRL_STORAGE_CONTAINER = tests/fixtures/crl WTF_CSRF_ENABLED = false STORAGE_PROVIDER=LOCAL PRESERVE_CONTEXT_ON_EXCEPTION = false +CSP=mock-test diff --git a/tests/domain/test_mock_csp.py b/tests/domain/test_mock_csp.py index 927bf304..27495f4c 100644 --- a/tests/domain/test_mock_csp.py +++ b/tests/domain/test_mock_csp.py @@ -2,12 +2,12 @@ import pytest from atst.domain.csp import MockCloudProvider -CREDENTIALS = MockCloudProvider()._auth_credentials +CREDENTIALS = MockCloudProvider(config={})._auth_credentials @pytest.fixture def mock_csp(): - return MockCloudProvider(with_delay=False, with_failure=False) + return MockCloudProvider(config={}, with_delay=False, with_failure=False) def test_create_environment(mock_csp: MockCloudProvider):