diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md
index dad452d09..4a5b50d8a 100644
--- a/IMPLEMENTATION_COVERAGE.md
+++ b/IMPLEMENTATION_COVERAGE.md
@@ -5723,6 +5723,31 @@
- [ ] validate_resource_policy
+## service-quotas
+
+10% implemented
+
+- [ ] associate_service_quota_template
+- [ ] delete_service_quota_increase_request_from_template
+- [ ] disassociate_service_quota_template
+- [ ] get_association_for_service_quota_template
+- [ ] get_aws_default_service_quota
+- [ ] get_requested_service_quota_change
+- [X] get_service_quota
+- [ ] get_service_quota_increase_request_from_template
+- [X] list_aws_default_service_quotas
+- [ ] list_requested_service_quota_change_history
+- [ ] list_requested_service_quota_change_history_by_quota
+- [ ] list_service_quota_increase_requests_in_template
+- [ ] list_service_quotas
+- [ ] list_services
+- [ ] list_tags_for_resource
+- [ ] put_service_quota_increase_request_into_template
+- [ ] request_service_quota_increase
+- [ ] tag_resource
+- [ ] untag_resource
+
+
## servicediscovery
61% implemented
@@ -6537,7 +6562,6 @@
- schemas
- securityhub
- serverlessrepo
-- service-quotas
- servicecatalog
- servicecatalog-appregistry
- sesv2
diff --git a/MANIFEST.in b/MANIFEST.in
index 16002563f..c4c45ceb7 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -9,6 +9,7 @@ include moto/ec2/resources/amis.json
include moto/cognitoidp/resources/*.json
include moto/dynamodb/parsing/reserved_keywords.txt
include moto/moto_api/_internal/*
+include moto/servicequotas/resources/*/*.json
include moto/ssm/resources/*.json
include moto/ssm/resources/ami-amazon-linux-latest/*.json
include moto/support/resources/*.json
diff --git a/docs/docs/services/service-quotas.rst b/docs/docs/services/service-quotas.rst
new file mode 100644
index 000000000..bbbd58af3
--- /dev/null
+++ b/docs/docs/services/service-quotas.rst
@@ -0,0 +1,54 @@
+.. _implementedservice_service-quotas:
+
+.. |start-h3| raw:: html
+
+
+
+.. |end-h3| raw:: html
+
+
+
+==============
+service-quotas
+==============
+
+.. autoclass:: moto.servicequotas.models.ServiceQuotasBackend
+
+|start-h3| Example usage |end-h3|
+
+.. sourcecode:: python
+
+ @mock_servicequotas
+ def test_servicequotas_behaviour:
+ boto3.client("service-quotas")
+ ...
+
+
+
+|start-h3| Implemented features for this service |end-h3|
+
+- [ ] associate_service_quota_template
+- [ ] delete_service_quota_increase_request_from_template
+- [ ] disassociate_service_quota_template
+- [ ] get_association_for_service_quota_template
+- [ ] get_aws_default_service_quota
+- [ ] get_requested_service_quota_change
+- [X] get_service_quota
+- [ ] get_service_quota_increase_request_from_template
+- [X] list_aws_default_service_quotas
+
+ The ServiceCodes that are currently implemented are: vpc
+ Pagination is not yet implemented.
+
+
+- [ ] list_requested_service_quota_change_history
+- [ ] list_requested_service_quota_change_history_by_quota
+- [ ] list_service_quota_increase_requests_in_template
+- [ ] list_service_quotas
+- [ ] list_services
+- [ ] list_tags_for_resource
+- [ ] put_service_quota_increase_request_into_template
+- [ ] request_service_quota_increase
+- [ ] tag_resource
+- [ ] untag_resource
+
diff --git a/moto/__init__.py b/moto/__init__.py
index efabfa827..660ef0ee2 100644
--- a/moto/__init__.py
+++ b/moto/__init__.py
@@ -138,6 +138,9 @@ mock_s3control = lazy_load(".s3control", "mock_s3control")
mock_sagemaker = lazy_load(".sagemaker", "mock_sagemaker")
mock_sdb = lazy_load(".sdb", "mock_sdb")
mock_secretsmanager = lazy_load(".secretsmanager", "mock_secretsmanager")
+mock_servicequotas = lazy_load(
+ ".servicequotas", "mock_servicequotas", boto3_name="service-quotas"
+)
mock_ses = lazy_load(".ses", "mock_ses")
mock_servicediscovery = lazy_load(".servicediscovery", "mock_servicediscovery")
mock_signer = lazy_load(".signer", "mock_signer", boto3_name="signer")
diff --git a/moto/backend_index.py b/moto/backend_index.py
index d634817fd..9bc4d4765 100644
--- a/moto/backend_index.py
+++ b/moto/backend_index.py
@@ -148,6 +148,7 @@ backend_url_patterns = [
"servicediscovery",
re.compile("https?://servicediscovery\\.(.+)\\.amazonaws\\.com"),
),
+ ("service-quotas", re.compile("https?://servicequotas\\.(.+)\\.amazonaws\\.com")),
("ses", re.compile("https?://email\\.(.+)\\.amazonaws\\.com")),
("ses", re.compile("https?://ses\\.(.+)\\.amazonaws\\.com")),
("signer", re.compile("https?://signer\\.(.+)\\.amazonaws\\.com")),
diff --git a/moto/servicequotas/__init__.py b/moto/servicequotas/__init__.py
new file mode 100644
index 000000000..d8e8601ef
--- /dev/null
+++ b/moto/servicequotas/__init__.py
@@ -0,0 +1,5 @@
+"""servicequotas module initialization; sets value for base decorator."""
+from .models import servicequotas_backends
+from ..core.models import base_decorator
+
+mock_servicequotas = base_decorator(servicequotas_backends)
diff --git a/moto/servicequotas/exceptions.py b/moto/servicequotas/exceptions.py
new file mode 100644
index 000000000..b84cae248
--- /dev/null
+++ b/moto/servicequotas/exceptions.py
@@ -0,0 +1,10 @@
+"""Exceptions raised by the servicequotas service."""
+from moto.core.exceptions import JsonRESTError
+
+
+class NoSuchResource(JsonRESTError):
+ def __init__(self) -> None:
+ super().__init__(
+ "NoSuchResourceException",
+ "This service is not available in the current Region. Choose a different Region or a different service.",
+ )
diff --git a/moto/servicequotas/models.py b/moto/servicequotas/models.py
new file mode 100644
index 000000000..1860a4734
--- /dev/null
+++ b/moto/servicequotas/models.py
@@ -0,0 +1,35 @@
+"""ServiceQuotasBackend class with methods for supported APIs."""
+
+from moto.core import BaseBackend
+from moto.core.utils import BackendDict
+from typing import Any, Dict, List
+from .exceptions import NoSuchResource
+from .resources.default_quotas.vpc import VPC_DEFAULT_QUOTAS
+
+
+class ServiceQuotasBackend(BaseBackend):
+ """Implementation of ServiceQuotas APIs."""
+
+ def __init__(self, region_name: str, account_id: str):
+ super().__init__(region_name, account_id)
+
+ def list_aws_default_service_quotas(
+ self, service_code: str
+ ) -> List[Dict[str, Any]]:
+ """
+ The ServiceCodes that are currently implemented are: vpc
+ Pagination is not yet implemented.
+ """
+ if service_code == "vpc":
+ return VPC_DEFAULT_QUOTAS
+ raise NoSuchResource
+
+ def get_service_quota(self, service_code: str, quota_code: str) -> Dict[str, Any]:
+ if service_code == "vpc":
+ for quota in VPC_DEFAULT_QUOTAS:
+ if quota["QuotaCode"] == quota_code:
+ return quota
+ raise NoSuchResource
+
+
+servicequotas_backends = BackendDict(ServiceQuotasBackend, "service-quotas")
diff --git a/moto/servicequotas/resources/__init__.py b/moto/servicequotas/resources/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/moto/servicequotas/resources/default_quotas/__init__.py b/moto/servicequotas/resources/default_quotas/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/moto/servicequotas/resources/default_quotas/vpc.py b/moto/servicequotas/resources/default_quotas/vpc.py
new file mode 100644
index 000000000..896aeb879
--- /dev/null
+++ b/moto/servicequotas/resources/default_quotas/vpc.py
@@ -0,0 +1,277 @@
+VPC_DEFAULT_QUOTAS = [
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-7E9ECCDB",
+ "QuotaCode": "L-7E9ECCDB",
+ "QuotaName": "Active VPC peering connections per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 50.0,
+ },
+ {
+ "Adjustable": False,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-3248932A",
+ "QuotaCode": "L-3248932A",
+ "QuotaName": "Characters per VPC endpoint policy",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 20480.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-45FE3B85",
+ "QuotaCode": "L-45FE3B85",
+ "QuotaName": "Egress-only internet gateways per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-1B52E74A",
+ "QuotaCode": "L-1B52E74A",
+ "QuotaName": "Gateway VPC endpoints per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 20.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-83CA0A9D",
+ "QuotaCode": "L-83CA0A9D",
+ "QuotaName": "IPv4 CIDR blocks per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-085A6257",
+ "QuotaCode": "L-085A6257",
+ "QuotaName": "IPv6 CIDR blocks per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-0EA8095F",
+ "QuotaCode": "L-0EA8095F",
+ "QuotaName": "Inbound or outbound rules per security group",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 60.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-29B6F2EB",
+ "QuotaCode": "L-29B6F2EB",
+ "QuotaName": "Interface VPC endpoints per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 50.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-A4707A72",
+ "QuotaCode": "L-A4707A72",
+ "QuotaName": "Internet gateways per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-FE5A380F",
+ "QuotaCode": "L-FE5A380F",
+ "QuotaName": "NAT gateways per Availability Zone",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-B4A6D682",
+ "QuotaCode": "L-B4A6D682",
+ "QuotaName": "Network ACLs per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 200.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-BB24F6E5",
+ "QuotaCode": "L-BB24F6E5",
+ "QuotaName": "Network Address Usage",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 64000.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-DF5E4CA3",
+ "QuotaCode": "L-DF5E4CA3",
+ "QuotaName": "Network interfaces per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5000.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-DC9F7029",
+ "QuotaCode": "L-DC9F7029",
+ "QuotaName": "Outstanding VPC peering connection requests",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 25.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-2C462E13",
+ "QuotaCode": "L-2C462E13",
+ "QuotaName": "Participant accounts per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 100.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-CD17FD4B",
+ "QuotaCode": "L-CD17FD4B",
+ "QuotaName": "Peered Network Address Usage",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 128000.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-589F43AA",
+ "QuotaCode": "L-589F43AA",
+ "QuotaName": "Route tables per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 200.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-93826ACB",
+ "QuotaCode": "L-93826ACB",
+ "QuotaName": "Routes per route table",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 50.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-2AEEBF1A",
+ "QuotaCode": "L-2AEEBF1A",
+ "QuotaName": "Rules per network ACL",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 20.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-2AFB9258",
+ "QuotaCode": "L-2AFB9258",
+ "QuotaName": "Security groups per network interface",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-407747CB",
+ "QuotaCode": "L-407747CB",
+ "QuotaName": "Subnets per VPC",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 200.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-44499CD2",
+ "QuotaCode": "L-44499CD2",
+ "QuotaName": "Subnets that can be shared with an account",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 100.0,
+ },
+ {
+ "Adjustable": False,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-8312C5BB",
+ "QuotaCode": "L-8312C5BB",
+ "QuotaName": "VPC peering connection request expiry hours",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 168.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-E79EC296",
+ "QuotaCode": "L-E79EC296",
+ "QuotaName": "VPC security groups per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 2500.0,
+ },
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-F678F1CE",
+ "QuotaCode": "L-F678F1CE",
+ "QuotaName": "VPCs per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ },
+]
diff --git a/moto/servicequotas/responses.py b/moto/servicequotas/responses.py
new file mode 100644
index 000000000..40442e4e6
--- /dev/null
+++ b/moto/servicequotas/responses.py
@@ -0,0 +1,33 @@
+"""Handles incoming servicequotas requests, invokes methods, returns responses."""
+import json
+
+from moto.core.responses import BaseResponse
+from .models import servicequotas_backends, ServiceQuotasBackend
+
+
+class ServiceQuotasResponse(BaseResponse):
+ """Handler for ServiceQuotas requests and responses."""
+
+ def __init__(self) -> None:
+ super().__init__(service_name="service-quotas")
+
+ @property
+ def backend(self) -> ServiceQuotasBackend:
+ """Return backend instance specific for this region."""
+ return servicequotas_backends[self.current_account][self.region]
+
+ def list_aws_default_service_quotas(self) -> str:
+ params = json.loads(self.body)
+ service_code = str(params.get("ServiceCode"))
+ quotas = self.backend.list_aws_default_service_quotas(service_code)
+ return json.dumps(dict(Quotas=quotas))
+
+ def get_service_quota(self) -> str:
+ params = json.loads(self.body)
+ service_code = str(params.get("ServiceCode"))
+ quota_code = str(params.get("QuotaCode"))
+ quota = self.backend.get_service_quota(
+ service_code=service_code,
+ quota_code=quota_code,
+ )
+ return json.dumps(dict(Quota=quota))
diff --git a/moto/servicequotas/urls.py b/moto/servicequotas/urls.py
new file mode 100644
index 000000000..a6a870cf6
--- /dev/null
+++ b/moto/servicequotas/urls.py
@@ -0,0 +1,11 @@
+"""servicequotas base URL and path."""
+from .responses import ServiceQuotasResponse
+
+url_bases = [
+ r"https?://servicequotas\.(.+)\.amazonaws\.com",
+]
+
+
+url_paths = {
+ "{0}/$": ServiceQuotasResponse.dispatch,
+}
diff --git a/tests/terraformtests/terraform-tests.success.txt b/tests/terraformtests/terraform-tests.success.txt
index c2eaa21aa..d66058a7d 100644
--- a/tests/terraformtests/terraform-tests.success.txt
+++ b/tests/terraformtests/terraform-tests.success.txt
@@ -87,10 +87,7 @@ ec2:
- TestAccEC2CarrierGateway_
- TestAccEC2InstanceTypeOfferingDataSource_
- TestAccEC2InstanceTypeOfferingsDataSource_
- - TestAccEC2InternetGateway_
- - TestAccEC2NATGateway_
- TestAccEC2RouteTableAssociation_
- - TestAccEC2SecurityGroups
- TestAccEC2SpotInstanceRequest_disappears
- TestAccEC2SpotInstanceRequest_interruptUpdate
- TestAccEC2VPCEndpointService_
@@ -99,6 +96,42 @@ ec2:
- TestAccEC2VPNGateway_
- TestAccEC2VPNGatewayAttachment_
- TestAccVPC_
+ - TestAccVPCEgressOnlyInternetGateway_
+ - TestAccVPCInternetGateway
+ - TestAccVPCNATGateway_
+ - TestAccVPCSecurityGroupDataSource_basic
+ - TestAccVPCSecurityGroupRule_
+ - TestAccVPCSecurityGroup_allowAll
+ - TestAccVPCSecurityGroup_basic
+ - TestAccVPCSecurityGroup_change
+ - TestAccVPCSecurityGroup_cidrAndGroups
+ - TestAccVPCSecurityGroup_defaultEgressVPC
+ - TestAccVPCSecurityGroup_disappears
+ - TestAccVPCSecurityGroup_driftComplex
+ - TestAccVPCSecurityGroup_egressMode
+ - TestAccVPCSecurityGroup_egressWithPrefixList
+ - TestAccVPCSecurityGroup_failWithDiffMismatch
+ - TestAccVPCSecurityGroup_ingressMode
+ - TestAccVPCSecurityGroup_ingressWithCIDRAndSGsVPC
+ - TestAccVPCSecurityGroup_ingressWithPrefixList
+ - TestAccVPCSecurityGroup_invalidCIDRBlock
+ - TestAccVPCSecurityGroup_ipRangeAndSecurityGroupWithSameRules
+ - TestAccVPCSecurityGroup_ipRangesWithSameRules
+ - TestAccVPCSecurityGroup_ipv4AndIPv6Egress
+ - TestAccVPCSecurityGroup_ipv6
+ - TestAccVPCSecurityGroup_multiIngress
+ - TestAccVPCSecurityGroup_nameGenerated
+ - TestAccVPCSecurityGroup_namePrefix
+ - TestAccVPCSecurityGroup_namePrefixTerraform
+ - TestAccVPCSecurityGroup_nameTerraformPrefix
+ - TestAccVPCSecurityGroup_noVPC
+ - TestAccVPCSecurityGroup_ruleDescription
+ - TestAccVPCSecurityGroup_ruleGathering
+ - TestAccVPCSecurityGroup_self
+ - TestAccVPCSecurityGroup_sourceSecurityGroup
+ - TestAccVPCSecurityGroup_tags
+ - TestAccVPCSecurityGroup_vpc
+ - TestAccVPCSecurityGroups
ecr:
- TestAccECRLifecyclePolicy
- TestAccECRRegistryPolicy
diff --git a/tests/test_servicequotas/__init__.py b/tests/test_servicequotas/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_servicequotas/test_servicequotas.py b/tests/test_servicequotas/test_servicequotas.py
new file mode 100644
index 000000000..0380af28a
--- /dev/null
+++ b/tests/test_servicequotas/test_servicequotas.py
@@ -0,0 +1,77 @@
+"""Unit tests for servicequotas-supported APIs."""
+import boto3
+import pytest
+import sure # noqa # pylint: disable=unused-import
+from moto import mock_servicequotas
+from botocore.exceptions import ClientError
+
+# See our Development Tips on writing tests for hints on how to write good tests:
+# http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html
+
+
+@mock_servicequotas
+def test_list_aws_default_service_quotas():
+ client = boto3.client("service-quotas", region_name="eu-west-1")
+ resp = client.list_aws_default_service_quotas(ServiceCode="vpc")
+
+ resp.should.have.key("Quotas").length_of(25)
+
+ resp["Quotas"].should.contain(
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-2AFB9258",
+ "QuotaCode": "L-2AFB9258",
+ "QuotaName": "Security groups per network interface",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ }
+ )
+ resp["Quotas"].should.contain(
+ {
+ "Adjustable": True,
+ "GlobalQuota": False,
+ "QuotaArn": "arn:aws:servicequotas:eu-west-1::vpc/L-F678F1CE",
+ "QuotaCode": "L-F678F1CE",
+ "QuotaName": "VPCs per Region",
+ "ServiceCode": "vpc",
+ "ServiceName": "Amazon Virtual Private Cloud (Amazon VPC)",
+ "Unit": "None",
+ "Value": 5.0,
+ }
+ )
+
+
+@mock_servicequotas
+def test_list_defaults_for_unknown_service():
+ client = boto3.client("service-quotas", "us-east-1")
+
+ with pytest.raises(ClientError) as exc:
+ client.list_aws_default_service_quotas(ServiceCode="unknown")
+ err = exc.value.response["Error"]
+ err["Code"].should.equal("NoSuchResourceException")
+ err["Message"].should.equal(
+ "This service is not available in the current Region. Choose a different Region or a different service."
+ )
+
+
+@mock_servicequotas
+def test_get_service_quota():
+ client = boto3.client("service-quotas", region_name="us-east-2")
+ quotas = client.list_aws_default_service_quotas(ServiceCode="vpc")["Quotas"]
+
+ for quota in quotas:
+ resp = client.get_service_quota(ServiceCode="vpc", QuotaCode=quota["QuotaCode"])
+ quota.should.equal(resp["Quota"])
+
+
+@mock_servicequotas
+def test_get_unknown_service_quota():
+ client = boto3.client("service-quotas", region_name="us-east-2")
+
+ with pytest.raises(ClientError) as exc:
+ client.get_service_quota(ServiceCode="vpc", QuotaCode="unknown")
+ err = exc.value.response["Error"]
+ err["Code"].should.equal("NoSuchResourceException")