| 
									
										
										
										
											2022-06-28 13:33:00 +02:00
										 |  |  | """Unit tests for emrserverless-supported APIs.""" | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | from datetime import datetime, timezone | 
					
						
							|  |  |  | from contextlib import contextmanager | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import boto3 | 
					
						
							|  |  |  | import pytest | 
					
						
							|  |  |  | import sure  # noqa # pylint: disable=unused-import | 
					
						
							|  |  |  | from botocore.exceptions import ClientError | 
					
						
							|  |  |  | from moto import mock_emrserverless, settings | 
					
						
							| 
									
										
										
										
											2022-08-13 09:49:43 +00:00
										 |  |  | from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID | 
					
						
							| 
									
										
										
										
											2022-06-28 13:33:00 +02:00
										 |  |  | from moto.emrserverless import REGION as DEFAULT_REGION | 
					
						
							|  |  |  | from moto.emrserverless import RELEASE_LABEL as DEFAULT_RELEASE_LABEL | 
					
						
							|  |  |  | from unittest.mock import patch | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @contextmanager | 
					
						
							|  |  |  | def does_not_raise(): | 
					
						
							|  |  |  |     yield | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-04 16:28:30 +00:00
										 |  |  | @pytest.fixture(scope="function", name="client") | 
					
						
							|  |  |  | def fixture_client(): | 
					
						
							| 
									
										
										
										
											2022-06-28 13:33:00 +02:00
										 |  |  |     with mock_emrserverless(): | 
					
						
							|  |  |  |         yield boto3.client("emr-serverless", region_name=DEFAULT_REGION) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-04 16:28:30 +00:00
										 |  |  | @pytest.fixture(scope="function", name="application_factory") | 
					
						
							|  |  |  | def fixture_application_factory(client): | 
					
						
							| 
									
										
										
										
											2022-06-28 13:33:00 +02:00
										 |  |  |     application_list = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if settings.TEST_SERVER_MODE: | 
					
						
							|  |  |  |         resp = client.create_application( | 
					
						
							|  |  |  |             name="test-emr-serverless-application-STARTED", | 
					
						
							|  |  |  |             type="SPARK", | 
					
						
							|  |  |  |             releaseLabel=DEFAULT_RELEASE_LABEL, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         application_list.append(resp["applicationId"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         resp = client.create_application( | 
					
						
							|  |  |  |             name="test-emr-serverless-application-STOPPED", | 
					
						
							|  |  |  |             type="SPARK", | 
					
						
							|  |  |  |             releaseLabel=DEFAULT_RELEASE_LABEL, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         client.stop_application(applicationId=resp["applicationId"]) | 
					
						
							|  |  |  |         application_list.append(resp["applicationId"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         application_state = [ | 
					
						
							|  |  |  |             "STARTED", | 
					
						
							|  |  |  |             "STOPPED", | 
					
						
							|  |  |  |             "CREATING", | 
					
						
							|  |  |  |             "CREATED", | 
					
						
							|  |  |  |             "STARTING", | 
					
						
							|  |  |  |             "STOPPING", | 
					
						
							|  |  |  |             "TERMINATED", | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for state in application_state: | 
					
						
							|  |  |  |             with patch("moto.emrserverless.models.APPLICATION_STATUS", state): | 
					
						
							|  |  |  |                 resp = client.create_application( | 
					
						
							|  |  |  |                     name=f"test-emr-serverless-application-{state}", | 
					
						
							|  |  |  |                     type="SPARK", | 
					
						
							|  |  |  |                     releaseLabel=DEFAULT_RELEASE_LABEL, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 application_list.append(resp["applicationId"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     yield application_list | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestCreateApplication: | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     @mock_emrserverless | 
					
						
							|  |  |  |     def test_create_application(client): | 
					
						
							|  |  |  |         resp = client.create_application( | 
					
						
							|  |  |  |             name="test-emr-serverless-application", | 
					
						
							|  |  |  |             type="SPARK", | 
					
						
							|  |  |  |             releaseLabel=DEFAULT_RELEASE_LABEL, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert resp["name"] == "test-emr-serverless-application" | 
					
						
							|  |  |  |         assert re.match(r"[a-z,0-9]{16}", resp["applicationId"]) | 
					
						
							|  |  |  |         assert ( | 
					
						
							|  |  |  |             resp["arn"] | 
					
						
							|  |  |  |             == f"arn:aws:emr-containers:us-east-1:{ACCOUNT_ID}:/applications/{resp['applicationId']}" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     @mock_emrserverless | 
					
						
							|  |  |  |     def test_create_application_incorrect_type(client): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             client.create_application( | 
					
						
							|  |  |  |                 name="test-emr-serverless-application", | 
					
						
							|  |  |  |                 type="SPARK3", | 
					
						
							|  |  |  |                 releaseLabel=DEFAULT_RELEASE_LABEL, | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert err["Code"] == "ValidationException" | 
					
						
							|  |  |  |         assert err["Message"] == "Unsupported engine SPARK3" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     @mock_emrserverless | 
					
						
							|  |  |  |     def test_create_application_incorrect_release_label(client): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             client.create_application( | 
					
						
							|  |  |  |                 name="test-emr-serverless-application", | 
					
						
							|  |  |  |                 type="SPARK", | 
					
						
							|  |  |  |                 releaseLabel="emr-fake", | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert err["Code"] == "ValidationException" | 
					
						
							|  |  |  |         assert ( | 
					
						
							|  |  |  |             err["Message"] | 
					
						
							|  |  |  |             == "Type 'SPARK' is not supported for release label 'emr-fake' or release label does not exist" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestDeleteApplication: | 
					
						
							|  |  |  |     @pytest.fixture(autouse=True) | 
					
						
							|  |  |  |     def _setup_environment(self, client, application_factory): | 
					
						
							|  |  |  |         self.client = client | 
					
						
							|  |  |  |         self.application_ids = application_factory | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @pytest.mark.parametrize( | 
					
						
							|  |  |  |         "index,status,expectation", | 
					
						
							|  |  |  |         argvalues=( | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 (0, "STARTED", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (1, "STOPPED", does_not_raise()), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             if settings.TEST_SERVER_MODE | 
					
						
							|  |  |  |             else [ | 
					
						
							|  |  |  |                 (0, "STARTED", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (1, "STOPPED", does_not_raise()), | 
					
						
							|  |  |  |                 (2, "CREATING", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (3, "CREATED", does_not_raise()), | 
					
						
							|  |  |  |                 (4, "STARTING", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (5, "STOPPING", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (6, "TERMINATED", pytest.raises(ClientError)), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     def test_valid_application_id(self, index, status, expectation): | 
					
						
							|  |  |  |         with expectation as exc: | 
					
						
							|  |  |  |             resp = self.client.delete_application( | 
					
						
							|  |  |  |                 applicationId=self.application_ids[index] | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if exc: | 
					
						
							|  |  |  |             err = exc.value.response["Error"] | 
					
						
							|  |  |  |             assert err["Code"] == "ValidationException" | 
					
						
							|  |  |  |             assert ( | 
					
						
							|  |  |  |                 err["Message"] | 
					
						
							|  |  |  |                 == f"Application {self.application_ids[index]} must be in one of the following statuses [CREATED, STOPPED]. Current status: {status}" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             assert resp is not None | 
					
						
							|  |  |  |             assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalid_application_id(self): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.delete_application(applicationId="fake_application_id") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         assert err["Code"] == "ResourceNotFoundException" | 
					
						
							|  |  |  |         assert err["Message"] == "Application fake_application_id does not exist" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestGetApplication: | 
					
						
							|  |  |  |     @pytest.fixture(autouse=True) | 
					
						
							|  |  |  |     def _setup_environment(self, client): | 
					
						
							|  |  |  |         self.client = client | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def get_expected_resp(application_id, extra_configuration): | 
					
						
							|  |  |  |         response = { | 
					
						
							|  |  |  |             "applicationId": application_id, | 
					
						
							|  |  |  |             "name": "test-emr-serverless-application", | 
					
						
							|  |  |  |             "arn": f"arn:aws:emr-containers:us-east-1:123456789012:/applications/{application_id}", | 
					
						
							|  |  |  |             "releaseLabel": "emr-6.6.0", | 
					
						
							|  |  |  |             "type": "Spark", | 
					
						
							|  |  |  |             "state": "STARTED", | 
					
						
							|  |  |  |             "stateDetails": "", | 
					
						
							|  |  |  |             "autoStartConfiguration": {"enabled": True}, | 
					
						
							|  |  |  |             "autoStopConfiguration": {"enabled": True, "idleTimeoutMinutes": 15}, | 
					
						
							|  |  |  |             "tags": {}, | 
					
						
							|  |  |  |             "createdAt": ( | 
					
						
							|  |  |  |                 datetime.today() | 
					
						
							|  |  |  |                 .replace(hour=0, minute=0, second=0, microsecond=0) | 
					
						
							|  |  |  |                 .replace(tzinfo=timezone.utc) | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             "updatedAt": ( | 
					
						
							|  |  |  |                 datetime.today() | 
					
						
							|  |  |  |                 .replace(hour=0, minute=0, second=0, microsecond=0) | 
					
						
							|  |  |  |                 .replace(tzinfo=timezone.utc) | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return {**response, **extra_configuration} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @pytest.mark.parametrize( | 
					
						
							|  |  |  |         "extra_configuration", | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             {}, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "initialCapacity": { | 
					
						
							|  |  |  |                     "Driver": { | 
					
						
							|  |  |  |                         "workerCount": 1, | 
					
						
							|  |  |  |                         "workerConfiguration": { | 
					
						
							|  |  |  |                             "cpu": "2 vCPU", | 
					
						
							|  |  |  |                             "memory": "4 GB", | 
					
						
							|  |  |  |                             "disk": "20 GB", | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "maximumCapacity": { | 
					
						
							|  |  |  |                     "cpu": "400 vCPU", | 
					
						
							|  |  |  |                     "memory": "1024 GB", | 
					
						
							|  |  |  |                     "disk": "1000 GB", | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "networkConfiguration": { | 
					
						
							|  |  |  |                     "subnetIds": ["subnet-0123456789abcdefg"], | 
					
						
							|  |  |  |                     "securityGroupIds": ["sg-0123456789abcdefg"], | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "initialCapacity": { | 
					
						
							|  |  |  |                     "Driver": { | 
					
						
							|  |  |  |                         "workerCount": 1, | 
					
						
							|  |  |  |                         "workerConfiguration": { | 
					
						
							|  |  |  |                             "cpu": "2 vCPU", | 
					
						
							|  |  |  |                             "memory": "4 GB", | 
					
						
							|  |  |  |                             "disk": "20 GB", | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "maximumCapacity": { | 
					
						
							|  |  |  |                     "cpu": "400 vCPU", | 
					
						
							|  |  |  |                     "memory": "1024 GB", | 
					
						
							|  |  |  |                     "disk": "1000 GB", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "networkConfiguration": { | 
					
						
							|  |  |  |                     "subnetIds": ["subnet-0123456789abcdefg"], | 
					
						
							|  |  |  |                     "securityGroupIds": ["sg-0123456789abcdefg"], | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     def test_filtering(self, extra_configuration): | 
					
						
							|  |  |  |         application_id = self.client.create_application( | 
					
						
							|  |  |  |             name="test-emr-serverless-application", | 
					
						
							|  |  |  |             type="SPARK", | 
					
						
							|  |  |  |             releaseLabel=DEFAULT_RELEASE_LABEL, | 
					
						
							|  |  |  |             **extra_configuration, | 
					
						
							|  |  |  |         )["applicationId"] | 
					
						
							|  |  |  |         expected_resp = self.get_expected_resp(application_id, extra_configuration) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         actual_resp = self.client.get_application(applicationId=application_id)[ | 
					
						
							|  |  |  |             "application" | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert actual_resp == expected_resp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalid_application_id(self): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.get_application(applicationId="fake_application_id") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         assert err["Code"] == "ResourceNotFoundException" | 
					
						
							|  |  |  |         assert err["Message"] == "Application fake_application_id does not exist" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestListApplication: | 
					
						
							|  |  |  |     @pytest.fixture(autouse=True) | 
					
						
							|  |  |  |     def _setup_environment(self, client, application_factory): | 
					
						
							|  |  |  |         self.client = client | 
					
						
							|  |  |  |         self.application_ids = application_factory | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_response_context(self): | 
					
						
							|  |  |  |         resp = self.client.list_applications() | 
					
						
							|  |  |  |         expected_resp = { | 
					
						
							|  |  |  |             "id": self.application_ids[0], | 
					
						
							|  |  |  |             "name": "test-emr-serverless-application-STARTED", | 
					
						
							|  |  |  |             "arn": f"arn:aws:emr-containers:us-east-1:123456789012:/applications/{self.application_ids[0]}", | 
					
						
							|  |  |  |             "releaseLabel": "emr-6.6.0", | 
					
						
							|  |  |  |             "type": "Spark", | 
					
						
							|  |  |  |             "state": "STARTED", | 
					
						
							|  |  |  |             "stateDetails": "", | 
					
						
							|  |  |  |             "createdAt": ( | 
					
						
							|  |  |  |                 datetime.today() | 
					
						
							|  |  |  |                 .replace(hour=0, minute=0, second=0, microsecond=0) | 
					
						
							|  |  |  |                 .replace(tzinfo=timezone.utc) | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             "updatedAt": ( | 
					
						
							|  |  |  |                 datetime.today() | 
					
						
							|  |  |  |                 .replace(hour=0, minute=0, second=0, microsecond=0) | 
					
						
							|  |  |  |                 .replace(tzinfo=timezone.utc) | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         actual_resp = [ | 
					
						
							|  |  |  |             app for app in resp["applications"] if app["id"] == expected_resp["id"] | 
					
						
							|  |  |  |         ][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert actual_resp == expected_resp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @pytest.mark.parametrize( | 
					
						
							|  |  |  |         "list_applications_args,job_count", | 
					
						
							|  |  |  |         argvalues=( | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 ({}, 2), | 
					
						
							|  |  |  |                 ({"states": ["STARTED"]}, 1), | 
					
						
							|  |  |  |                 ({"states": ["STARTED", "STOPPED"]}, 2), | 
					
						
							|  |  |  |                 ({"states": ["FOOBAA"]}, 0), | 
					
						
							|  |  |  |                 ({"maxResults": 1}, 1), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             if settings.TEST_SERVER_MODE | 
					
						
							|  |  |  |             else [ | 
					
						
							|  |  |  |                 ({}, 7), | 
					
						
							|  |  |  |                 ({"states": ["CREATED"]}, 1), | 
					
						
							|  |  |  |                 ({"states": ["CREATED", "STARTING"]}, 2), | 
					
						
							|  |  |  |                 ({"states": ["FOOBAA"]}, 0), | 
					
						
							|  |  |  |                 ({"maxResults": 1}, 1), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     def test_filtering(self, list_applications_args, job_count): | 
					
						
							|  |  |  |         resp = self.client.list_applications(**list_applications_args) | 
					
						
							|  |  |  |         assert len(resp["applications"]) == job_count | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_next_token(self): | 
					
						
							|  |  |  |         if settings.TEST_SERVER_MODE: | 
					
						
							|  |  |  |             resp = self.client.list_applications(maxResults=1) | 
					
						
							|  |  |  |             assert len(resp["applications"]) == 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             resp = self.client.list_applications(nextToken=resp["nextToken"]) | 
					
						
							|  |  |  |             assert len(resp["applications"]) == 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             resp = self.client.list_applications(maxResults=2) | 
					
						
							|  |  |  |             assert len(resp["applications"]) == 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             resp = self.client.list_applications(nextToken=resp["nextToken"]) | 
					
						
							|  |  |  |             assert len(resp["applications"]) == 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestStartApplication: | 
					
						
							|  |  |  |     @pytest.fixture(autouse=True) | 
					
						
							|  |  |  |     def _setup_environment(self, client, application_factory): | 
					
						
							|  |  |  |         self.client = client | 
					
						
							|  |  |  |         self.application_ids = application_factory | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_valid_application_id(self): | 
					
						
							|  |  |  |         resp = self.client.start_application(applicationId=self.application_ids[1]) | 
					
						
							|  |  |  |         assert resp is not None | 
					
						
							|  |  |  |         assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalid_application_id(self): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.start_application(applicationId="fake_application_id") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         assert err["Code"] == "ResourceNotFoundException" | 
					
						
							|  |  |  |         assert err["Message"] == "Application fake_application_id does not exist" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestStopApplication: | 
					
						
							|  |  |  |     @pytest.fixture(autouse=True) | 
					
						
							|  |  |  |     def _setup_environment(self, client, application_factory): | 
					
						
							|  |  |  |         self.client = client | 
					
						
							|  |  |  |         self.application_ids = application_factory | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_valid_application_id(self): | 
					
						
							|  |  |  |         resp = self.client.stop_application(applicationId=self.application_ids[1]) | 
					
						
							|  |  |  |         assert resp is not None | 
					
						
							|  |  |  |         assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalid_application_id(self): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.stop_application(applicationId="fake_application_id") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         assert err["Code"] == "ResourceNotFoundException" | 
					
						
							|  |  |  |         assert err["Message"] == "Application fake_application_id does not exist" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestUpdateApplication: | 
					
						
							|  |  |  |     @pytest.fixture(autouse=True) | 
					
						
							|  |  |  |     def _setup_environment(self, client, application_factory): | 
					
						
							|  |  |  |         self.client = client | 
					
						
							|  |  |  |         self.application_ids = application_factory | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def get_expected_resp(application_id, extra_configuration): | 
					
						
							|  |  |  |         response = { | 
					
						
							|  |  |  |             "applicationId": application_id, | 
					
						
							|  |  |  |             "name": "test-emr-serverless-application-STOPPED", | 
					
						
							|  |  |  |             "arn": f"arn:aws:emr-containers:us-east-1:123456789012:/applications/{application_id}", | 
					
						
							|  |  |  |             "releaseLabel": "emr-6.6.0", | 
					
						
							|  |  |  |             "type": "Spark", | 
					
						
							|  |  |  |             "state": "STOPPED", | 
					
						
							|  |  |  |             "stateDetails": "", | 
					
						
							|  |  |  |             "autoStartConfiguration": {"enabled": True}, | 
					
						
							|  |  |  |             "autoStopConfiguration": {"enabled": True, "idleTimeoutMinutes": 15}, | 
					
						
							|  |  |  |             "tags": {}, | 
					
						
							|  |  |  |             "createdAt": ( | 
					
						
							|  |  |  |                 datetime.today() | 
					
						
							|  |  |  |                 .replace(hour=0, minute=0, second=0, microsecond=0) | 
					
						
							|  |  |  |                 .replace(tzinfo=timezone.utc) | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             "updatedAt": ( | 
					
						
							|  |  |  |                 datetime.today() | 
					
						
							|  |  |  |                 .replace(hour=0, minute=0, second=0, microsecond=0) | 
					
						
							|  |  |  |                 .replace(tzinfo=timezone.utc) | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return {**response, **extra_configuration} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @pytest.mark.parametrize( | 
					
						
							|  |  |  |         "index,status,expectation", | 
					
						
							|  |  |  |         argvalues=( | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 (0, "STARTED", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (1, "STOPPED", does_not_raise()), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |             if settings.TEST_SERVER_MODE | 
					
						
							|  |  |  |             else [ | 
					
						
							|  |  |  |                 (0, "STARTED", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (1, "STOPPED", does_not_raise()), | 
					
						
							|  |  |  |                 (2, "CREATING", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (3, "CREATED", does_not_raise()), | 
					
						
							|  |  |  |                 (4, "STARTING", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (5, "STOPPING", pytest.raises(ClientError)), | 
					
						
							|  |  |  |                 (6, "TERMINATED", pytest.raises(ClientError)), | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     def test_application_status(self, index, status, expectation): | 
					
						
							|  |  |  |         with expectation as exc: | 
					
						
							|  |  |  |             resp = self.client.update_application( | 
					
						
							|  |  |  |                 applicationId=self.application_ids[index] | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if exc: | 
					
						
							|  |  |  |             err = exc.value.response["Error"] | 
					
						
							|  |  |  |             assert err["Code"] == "ValidationException" | 
					
						
							|  |  |  |             assert ( | 
					
						
							|  |  |  |                 err["Message"] | 
					
						
							|  |  |  |                 == f"Application {self.application_ids[index]} must be in one of the following statuses [CREATED, STOPPED]. Current status: {status}" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             assert resp is not None | 
					
						
							|  |  |  |             assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @pytest.mark.parametrize( | 
					
						
							|  |  |  |         "update_configuration", | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             {}, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "initialCapacity": { | 
					
						
							|  |  |  |                     "Driver": { | 
					
						
							|  |  |  |                         "workerCount": 1, | 
					
						
							|  |  |  |                         "workerConfiguration": { | 
					
						
							|  |  |  |                             "cpu": "2 vCPU", | 
					
						
							|  |  |  |                             "memory": "4 GB", | 
					
						
							|  |  |  |                             "disk": "20 GB", | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "maximumCapacity": { | 
					
						
							|  |  |  |                     "cpu": "400 vCPU", | 
					
						
							|  |  |  |                     "memory": "1024 GB", | 
					
						
							|  |  |  |                     "disk": "1000 GB", | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             {"autoStartConfiguration": {"enabled": False}}, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "autoStopConfiguration": { | 
					
						
							|  |  |  |                     "enabled": False, | 
					
						
							|  |  |  |                     "idleTimeoutMinutes": 5, | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "networkConfiguration": { | 
					
						
							|  |  |  |                     "subnetIds": ["subnet-0123456789abcdefg"], | 
					
						
							|  |  |  |                     "securityGroupIds": ["sg-0123456789abcdefg"], | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "initialCapacity": { | 
					
						
							|  |  |  |                     "Driver": { | 
					
						
							|  |  |  |                         "workerCount": 1, | 
					
						
							|  |  |  |                         "workerConfiguration": { | 
					
						
							|  |  |  |                             "cpu": "2 vCPU", | 
					
						
							|  |  |  |                             "memory": "4 GB", | 
					
						
							|  |  |  |                             "disk": "20 GB", | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "maximumCapacity": { | 
					
						
							|  |  |  |                     "cpu": "400 vCPU", | 
					
						
							|  |  |  |                     "memory": "1024 GB", | 
					
						
							|  |  |  |                     "disk": "1000 GB", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "autoStartConfiguration": {"enabled": False}, | 
					
						
							|  |  |  |                 "autoStopConfiguration": { | 
					
						
							|  |  |  |                     "enabled": False, | 
					
						
							|  |  |  |                     "idleTimeoutMinutes": 5, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "networkConfiguration": { | 
					
						
							|  |  |  |                     "subnetIds": ["subnet-0123456789abcdefg"], | 
					
						
							|  |  |  |                     "securityGroupIds": ["sg-0123456789abcdefg"], | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     def test_valid_update(self, update_configuration): | 
					
						
							|  |  |  |         expected_resp = self.get_expected_resp( | 
					
						
							|  |  |  |             self.application_ids[1], update_configuration | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         actual_resp = self.client.update_application( | 
					
						
							|  |  |  |             applicationId=self.application_ids[1], **update_configuration | 
					
						
							|  |  |  |         )["application"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert actual_resp == expected_resp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_invalid_application_id(self): | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.update_application(applicationId="fake_application_id") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         assert err["Code"] == "ResourceNotFoundException" | 
					
						
							|  |  |  |         assert err["Message"] == "Application fake_application_id does not exist" |