import boto3 from botocore.exceptions import ClientError from moto import mock_cloudfront from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID from . import cloudfront_test_scaffolding as scaffold import pytest import sure # noqa # pylint: disable=unused-import @mock_cloudfront def test_create_distribution_s3_minimum(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") resp = client.create_distribution(DistributionConfig=config) resp.should.have.key("Distribution") distribution = resp["Distribution"] distribution.should.have.key("Id") distribution.should.have.key("ARN").equals( f"arn:aws:cloudfront:{ACCOUNT_ID}:distribution/{distribution['Id']}" ) distribution.should.have.key("Status").equals("InProgress") distribution.should.have.key("LastModifiedTime") distribution.should.have.key("InProgressInvalidationBatches").equals(0) distribution.should.have.key("DomainName").should.contain(".cloudfront.net") distribution.should.have.key("ActiveTrustedSigners") signers = distribution["ActiveTrustedSigners"] signers.should.have.key("Enabled").equals(False) signers.should.have.key("Quantity").equals(0) distribution.should.have.key("ActiveTrustedKeyGroups") key_groups = distribution["ActiveTrustedKeyGroups"] key_groups.should.have.key("Enabled").equals(False) key_groups.should.have.key("Quantity").equals(0) distribution.should.have.key("DistributionConfig") config = distribution["DistributionConfig"] config.should.have.key("CallerReference").should.equal("ref") config.should.have.key("Aliases") config["Aliases"].should.have.key("Quantity").equals(0) config.should.have.key("Origins") origins = config["Origins"] origins.should.have.key("Quantity").equals(1) origins.should.have.key("Items").length_of(1) origin = origins["Items"][0] origin.should.have.key("Id").equals("origin1") origin.should.have.key("DomainName").equals("asdf.s3.us-east-1.amazonaws.com") origin.should.have.key("OriginPath").equals("/example") origin.should.have.key("CustomHeaders") origin["CustomHeaders"].should.have.key("Quantity").equals(0) origin.should.have.key("ConnectionAttempts").equals(3) origin.should.have.key("ConnectionTimeout").equals(10) origin.should.have.key("OriginShield").equals({"Enabled": False}) config.should.have.key("OriginGroups").equals({"Quantity": 0}) config.should.have.key("DefaultCacheBehavior") default_cache = config["DefaultCacheBehavior"] default_cache.should.have.key("TargetOriginId").should.equal("origin1") default_cache.should.have.key("TrustedSigners") signers = default_cache["TrustedSigners"] signers.should.have.key("Enabled").equals(False) signers.should.have.key("Quantity").equals(0) default_cache.should.have.key("TrustedKeyGroups") groups = default_cache["TrustedKeyGroups"] groups.should.have.key("Enabled").equals(False) groups.should.have.key("Quantity").equals(0) default_cache.should.have.key("ViewerProtocolPolicy").equals("allow-all") default_cache.should.have.key("AllowedMethods") methods = default_cache["AllowedMethods"] methods.should.have.key("Quantity").equals(2) methods.should.have.key("Items") set(methods["Items"]).should.equal({"HEAD", "GET"}) methods.should.have.key("CachedMethods") cached_methods = methods["CachedMethods"] cached_methods.should.have.key("Quantity").equals(2) set(cached_methods["Items"]).should.equal({"HEAD", "GET"}) default_cache.should.have.key("SmoothStreaming").equals(False) default_cache.should.have.key("Compress").equals(True) default_cache.should.have.key("LambdaFunctionAssociations").equals({"Quantity": 0}) default_cache.should.have.key("FunctionAssociations").equals({"Quantity": 0}) default_cache.should.have.key("FieldLevelEncryptionId").equals("") default_cache.should.have.key("CachePolicyId") config.should.have.key("CacheBehaviors").equals({"Quantity": 0}) config.should.have.key("CustomErrorResponses").equals({"Quantity": 0}) config.should.have.key("Comment").equals( "an optional comment that's not actually optional" ) config.should.have.key("Logging") logging = config["Logging"] logging.should.have.key("Enabled").equals(False) logging.should.have.key("IncludeCookies").equals(False) logging.should.have.key("Bucket").equals("") logging.should.have.key("Prefix").equals("") config.should.have.key("PriceClass").equals("PriceClass_All") config.should.have.key("Enabled").equals(False) config.should.have.key("WebACLId") config.should.have.key("HttpVersion").equals("http2") config.should.have.key("IsIPV6Enabled").equals(True) config.should.have.key("ViewerCertificate") cert = config["ViewerCertificate"] cert.should.have.key("CloudFrontDefaultCertificate").equals(True) cert.should.have.key("MinimumProtocolVersion").equals("TLSv1") cert.should.have.key("CertificateSource").equals("cloudfront") config.should.have.key("Restrictions") config["Restrictions"].should.have.key("GeoRestriction") restriction = config["Restrictions"]["GeoRestriction"] restriction.should.have.key("RestrictionType").equals("none") restriction.should.have.key("Quantity").equals(0) config.should.have.key("WebACLId") config.should.have.key("WebACLId").equals("") @mock_cloudfront def test_create_distribution_with_logging(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") config["Logging"] = { "Enabled": True, "IncludeCookies": True, "Bucket": "logging-bucket", "Prefix": "logging-bucket", } resp = client.create_distribution(DistributionConfig=config) resp.should.have.key("Distribution") distribution = resp["Distribution"] distribution.should.have.key("DistributionConfig") config = distribution["DistributionConfig"] config.should.have.key("Logging") logging = config["Logging"] logging.should.have.key("Enabled").equals(True) logging.should.have.key("IncludeCookies").equals(True) logging.should.have.key("Bucket").equals("logging-bucket") logging.should.have.key("Prefix").equals("logging-bucket") @mock_cloudfront def test_create_distribution_with_web_acl(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") config["WebACLId"] = "test-web-acl" resp = client.create_distribution(DistributionConfig=config) resp.should.have.key("Distribution") distribution = resp["Distribution"] distribution.should.have.key("DistributionConfig") config = distribution["DistributionConfig"] config.should.have.key("WebACLId") config.should.have.key("WebACLId").equals("test-web-acl") @mock_cloudfront def test_create_distribution_with_field_level_encryption_and_real_time_log_config_arn(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") real_time_log_config_arn = f"arn:aws:cloudfront::{ACCOUNT_ID}:realtime-log-config/ExampleNameForRealtimeLogConfig" config["DefaultCacheBehavior"]["RealtimeLogConfigArn"] = real_time_log_config_arn config["DefaultCacheBehavior"]["FieldLevelEncryptionId"] = "K3D5EWEUDCCXON" resp = client.create_distribution(DistributionConfig=config) resp.should.have.key("Distribution") distribution = resp["Distribution"] distribution.should.have.key("DistributionConfig") config = distribution["DistributionConfig"] config.should.have.key("DefaultCacheBehavior") default_cache = config["DefaultCacheBehavior"] default_cache.should.have.key("FieldLevelEncryptionId") default_cache.should.have.key("FieldLevelEncryptionId").equals("K3D5EWEUDCCXON") default_cache.should.have.key("RealtimeLogConfigArn") default_cache.should.have.key("RealtimeLogConfigArn").equals( real_time_log_config_arn ) @mock_cloudfront def test_create_distribution_with_georestriction(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") config["Restrictions"] = { "GeoRestriction": { "RestrictionType": "whitelist", "Quantity": 2, "Items": ["GB", "US"], } } resp = client.create_distribution(DistributionConfig=config) resp.should.have.key("Distribution") distribution = resp["Distribution"] distribution.should.have.key("DistributionConfig") config = distribution["DistributionConfig"] config.should.have.key("Restrictions") config["Restrictions"].should.have.key("GeoRestriction") restriction = config["Restrictions"]["GeoRestriction"] restriction.should.have.key("RestrictionType").equals("whitelist") restriction.should.have.key("Quantity").equals(2) restriction["Items"].should.contain("US") restriction["Items"].should.contain("GB") @mock_cloudfront def test_create_distribution_with_allowed_methods(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") config["DefaultCacheBehavior"]["AllowedMethods"] = { "Quantity": 3, "Items": ["GET", "HEAD", "PUT"], "CachedMethods": { "Quantity": 7, "Items": ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], }, } dist = client.create_distribution(DistributionConfig=config)["Distribution"] dist.should.have.key("DistributionConfig") cache = dist["DistributionConfig"]["DefaultCacheBehavior"] cache.should.have.key("AllowedMethods").equals( { "CachedMethods": { "Items": ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], "Quantity": 7, }, "Items": ["GET", "HEAD", "PUT"], "Quantity": 3, } ) @mock_cloudfront def test_create_distribution_with_origins(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") config["Origins"]["Items"][0]["ConnectionAttempts"] = 1 config["Origins"]["Items"][0]["ConnectionTimeout"] = 2 config["Origins"]["Items"][0]["OriginShield"] = { "Enabled": True, "OriginShieldRegion": "east", } dist = client.create_distribution(DistributionConfig=config)["Distribution"] origin = dist["DistributionConfig"]["Origins"]["Items"][0] origin.should.have.key("ConnectionAttempts").equals(1) origin.should.have.key("ConnectionTimeout").equals(2) origin.should.have.key("OriginShield").equals( {"Enabled": True, "OriginShieldRegion": "east"} ) @mock_cloudfront @pytest.mark.parametrize("compress", [True, False]) @pytest.mark.parametrize("qs", [True, False]) @pytest.mark.parametrize("smooth", [True, False]) @pytest.mark.parametrize("ipv6", [True, False]) def test_create_distribution_with_additional_fields(compress, qs, smooth, ipv6): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_distribution_config("ref") config["IsIPV6Enabled"] = ipv6 config["Aliases"] = {"Quantity": 2, "Items": ["alias1", "alias2"]} config["DefaultCacheBehavior"]["ForwardedValues"]["Cookies"] = { "Forward": "whitelist", "WhitelistedNames": {"Quantity": 1, "Items": ["x-amz-header"]}, } config["DefaultCacheBehavior"]["ForwardedValues"]["QueryString"] = qs config["DefaultCacheBehavior"]["Compress"] = compress config["DefaultCacheBehavior"]["MinTTL"] = 10 config["DefaultCacheBehavior"]["SmoothStreaming"] = smooth config["PriceClass"] = "PriceClass_100" resp = client.create_distribution(DistributionConfig=config) distribution = resp["Distribution"] distribution.should.have.key("DistributionConfig") config = distribution["DistributionConfig"] config.should.have.key("Aliases").equals( {"Items": ["alias1", "alias2"], "Quantity": 2} ) config.should.have.key("PriceClass").equals("PriceClass_100") config.should.have.key("IsIPV6Enabled").equals(ipv6) config["DefaultCacheBehavior"].should.have.key("Compress").equals(compress) config["DefaultCacheBehavior"].should.have.key("MinTTL").equals(10) config["DefaultCacheBehavior"].should.have.key("SmoothStreaming").equals(smooth) forwarded = config["DefaultCacheBehavior"]["ForwardedValues"] forwarded.should.have.key("QueryString").equals(qs) forwarded["Cookies"].should.have.key("Forward").equals("whitelist") forwarded["Cookies"].should.have.key("WhitelistedNames") forwarded["Cookies"]["WhitelistedNames"].should.have.key("Items").equals( ["x-amz-header"] ) @mock_cloudfront def test_create_distribution_returns_etag(): client = boto3.client("cloudfront", region_name="us-east-1") config = scaffold.example_distribution_config("ref") resp = client.create_distribution(DistributionConfig=config) dist_id = resp["Distribution"]["Id"] headers = resp["ResponseMetadata"]["HTTPHeaders"] headers.should.have.key("etag").length_of(13) headers.should.have.key("location").equals( f"https://cloudfront.amazonaws.com/2020-05-31/distribution/{dist_id}" ) @mock_cloudfront def test_create_distribution_needs_unique_caller_reference(): client = boto3.client("cloudfront", region_name="us-east-1") # Create standard distribution config = scaffold.example_distribution_config(ref="ref") dist1 = client.create_distribution(DistributionConfig=config) dist1_id = dist1["Distribution"]["Id"] # Try to create distribution with the same ref with pytest.raises(ClientError) as exc: client.create_distribution(DistributionConfig=config) err = exc.value.response["Error"] err["Code"].should.equal("DistributionAlreadyExists") err["Message"].should.equal( f"The caller reference that you are using to create a distribution is associated with another distribution. Already exists: {dist1_id}" ) # Creating another distribution with a different reference config = scaffold.example_distribution_config(ref="ref2") dist2 = client.create_distribution(DistributionConfig=config) dist1_id.shouldnt.equal(dist2["Distribution"]["Id"]) resp = client.list_distributions()["DistributionList"] resp.should.have.key("Quantity").equals(2) resp.should.have.key("Items").length_of(2) @mock_cloudfront def test_get_distribution_config_with_unknown_distribution_id(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: client.get_distribution_config(Id="unknown") metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(404) err = exc.value.response["Error"] err["Code"].should.equal("NoSuchDistribution") err["Message"].should.equal("The specified distribution does not exist.") @mock_cloudfront def test_get_distribution_config_with_mismatched_originid(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: client.create_distribution( DistributionConfig={ "CallerReference": "ref", "Origins": { "Quantity": 1, "Items": [{"Id": "origin1", "DomainName": "https://getmoto.org"}], }, "DefaultCacheBehavior": { "TargetOriginId": "asdf", "ViewerProtocolPolicy": "allow-all", }, "Comment": "an optional comment that's not actually optional", "Enabled": False, } ) metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(404) err = exc.value.response["Error"] err["Code"].should.equal("NoSuchOrigin") err["Message"].should.equal( "One or more of your origins or origin groups do not exist." ) @mock_cloudfront def test_create_origin_without_origin_config(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: client.create_distribution( DistributionConfig={ "CallerReference": "ref", "Origins": { "Quantity": 1, "Items": [{"Id": "origin1", "DomainName": "https://getmoto.org"}], }, "DefaultCacheBehavior": { "TargetOriginId": "origin1", "ViewerProtocolPolicy": "allow-all", }, "Comment": "an optional comment that's not actually optional", "Enabled": False, } ) metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(400) err = exc.value.response["Error"] err["Code"].should.equal("InvalidOrigin") err["Message"].should.equal( "The specified origin server does not exist or is not valid." ) @mock_cloudfront def test_create_distribution_with_invalid_s3_bucket(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: client.create_distribution( DistributionConfig={ "CallerReference": "ref", "Origins": { "Quantity": 1, "Items": [ { "Id": "origin1", "DomainName": "https://getmoto.org", "S3OriginConfig": {"OriginAccessIdentity": ""}, } ], }, "DefaultCacheBehavior": { "TargetOriginId": "origin1", "ViewerProtocolPolicy": "allow-all", }, "Comment": "an optional comment that's not actually optional", "Enabled": False, } ) metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(400) err = exc.value.response["Error"] err["Code"].should.equal("InvalidArgument") err["Message"].should.equal( "The parameter Origin DomainName does not refer to a valid S3 bucket." ) @mock_cloudfront def test_create_distribution_custom_config(): client = boto3.client("cloudfront", region_name="us-west-1") config = scaffold.example_dist_custom_config("ref") dist = client.create_distribution(DistributionConfig=config)["Distribution"][ "DistributionConfig" ] dist.should.have.key("Origins") dist["Origins"].should.have.key("Items").length_of(1) origin = dist["Origins"]["Items"][0] origin.should.have.key("CustomOriginConfig") custom_config = origin["CustomOriginConfig"] custom_config.should.have.key("HTTPPort").equals(80) custom_config.should.have.key("HTTPSPort").equals(443) custom_config.should.have.key("OriginProtocolPolicy").equals("http-only") custom_config.should.have.key("OriginSslProtocols").equals( {"Items": ["TLSv1", "SSLv3"], "Quantity": 2} ) @mock_cloudfront def test_list_distributions_without_any(): client = boto3.client("cloudfront", region_name="us-east-1") resp = client.list_distributions() resp.should.have.key("DistributionList") dlist = resp["DistributionList"] dlist.should.have.key("Marker").equals("") dlist.should.have.key("MaxItems").equals(100) dlist.should.have.key("IsTruncated").equals(False) dlist.should.have.key("Quantity").equals(0) dlist.shouldnt.have.key("Items") @mock_cloudfront def test_list_distributions(): client = boto3.client("cloudfront", region_name="us-east-1") config = scaffold.example_distribution_config(ref="ref1") dist1 = client.create_distribution(DistributionConfig=config)["Distribution"] config = scaffold.example_distribution_config(ref="ref2") dist2 = client.create_distribution(DistributionConfig=config)["Distribution"] resp = client.list_distributions() resp.should.have.key("DistributionList") dlist = resp["DistributionList"] dlist.should.have.key("Quantity").equals(2) dlist.should.have.key("Items").length_of(2) item1 = dlist["Items"][0] item1.should.have.key("Id").equals(dist1["Id"]) item1.should.have.key("ARN") item1.should.have.key("Status").equals("Deployed") item2 = dlist["Items"][1] item2.should.have.key("Id").equals(dist2["Id"]) item2.should.have.key("ARN") item2.should.have.key("Status").equals("Deployed") @mock_cloudfront def test_get_distribution(): client = boto3.client("cloudfront", region_name="us-east-1") # Create standard distribution config = scaffold.example_distribution_config(ref="ref") dist = client.create_distribution(DistributionConfig=config) dist_id = dist["Distribution"]["Id"] resp = client.get_distribution(Id=dist_id) headers = resp["ResponseMetadata"]["HTTPHeaders"] headers.should.have.key("etag").length_of(13) dist = resp["Distribution"] dist.should.have.key("Id").equals(dist_id) dist.should.have.key("Status").equals("Deployed") dist.should.have.key("DomainName").equals(dist["DomainName"]) dist.should.have.key("DistributionConfig") config = dist["DistributionConfig"] config.should.have.key("CallerReference").should.equal("ref") @mock_cloudfront def test_get_unknown_distribution(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: # Should have a second param, IfMatch, that contains the ETag of the most recent GetDistribution-request client.get_distribution(Id="unknown") metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(404) err = exc.value.response["Error"] err["Code"].should.equal("NoSuchDistribution") err["Message"].should.equal("The specified distribution does not exist.") @mock_cloudfront def test_delete_unknown_distribution(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: client.delete_distribution(Id="unknown", IfMatch="..") metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(404) err = exc.value.response["Error"] err["Code"].should.equal("NoSuchDistribution") err["Message"].should.equal("The specified distribution does not exist.") @mock_cloudfront def test_delete_distribution_without_ifmatch(): client = boto3.client("cloudfront", region_name="us-west-1") with pytest.raises(ClientError) as exc: # Should have a second param, IfMatch, that contains the ETag of the most recent GetDistribution-request client.delete_distribution(Id="...") metadata = exc.value.response["ResponseMetadata"] metadata["HTTPStatusCode"].should.equal(400) err = exc.value.response["Error"] err["Code"].should.equal("InvalidIfMatchVersion") err["Message"].should.equal( "The If-Match version is missing or not valid for the resource." ) @mock_cloudfront def test_delete_distribution_random_etag(): """ Etag validation is not implemented yet Calling the delete-method with any etag will pass """ client = boto3.client("cloudfront", region_name="us-east-1") # Create standard distribution config = scaffold.example_distribution_config(ref="ref") dist1 = client.create_distribution(DistributionConfig=config) dist_id = dist1["Distribution"]["Id"] client.delete_distribution(Id=dist_id, IfMatch="anything") with pytest.raises(ClientError) as exc: client.get_distribution(Id=dist_id) err = exc.value.response["Error"] err["Code"].should.equal("NoSuchDistribution") @mock_cloudfront def test_get_distribution_config(): client = boto3.client("cloudfront", region_name="us-east-1") # Create standard distribution config = scaffold.example_distribution_config(ref="ref") dist = client.create_distribution(DistributionConfig=config) dist_id = dist["Distribution"]["Id"] resp = client.get_distribution_config(Id=dist_id) resp.should.have.key("DistributionConfig") config = resp["DistributionConfig"] config.should.have.key("CallerReference").should.equal("ref") config.should.have.key("Aliases") config["Aliases"].should.have.key("Quantity").equals(0) config.should.have.key("Origins") origins = config["Origins"] origins.should.have.key("Quantity").equals(1) origins.should.have.key("Items").length_of(1) origin = origins["Items"][0] origin.should.have.key("Id").equals("origin1") origin.should.have.key("DomainName").equals("asdf.s3.us-east-1.amazonaws.com") origin.should.have.key("OriginPath").equals("/example") origin.should.have.key("CustomHeaders") origin["CustomHeaders"].should.have.key("Quantity").equals(0) origin.should.have.key("ConnectionAttempts").equals(3) origin.should.have.key("ConnectionTimeout").equals(10) origin.should.have.key("OriginShield").equals({"Enabled": False}) config.should.have.key("OriginGroups").equals({"Quantity": 0}) config.should.have.key("DefaultCacheBehavior") default_cache = config["DefaultCacheBehavior"] default_cache.should.have.key("TargetOriginId").should.equal("origin1") default_cache.should.have.key("TrustedSigners") signers = default_cache["TrustedSigners"] signers.should.have.key("Enabled").equals(False) signers.should.have.key("Quantity").equals(0) default_cache.should.have.key("TrustedKeyGroups") groups = default_cache["TrustedKeyGroups"] groups.should.have.key("Enabled").equals(False) groups.should.have.key("Quantity").equals(0) default_cache.should.have.key("ViewerProtocolPolicy").equals("allow-all") default_cache.should.have.key("AllowedMethods") methods = default_cache["AllowedMethods"] methods.should.have.key("Quantity").equals(2) methods.should.have.key("Items") set(methods["Items"]).should.equal({"HEAD", "GET"}) methods.should.have.key("CachedMethods") cached_methods = methods["CachedMethods"] cached_methods.should.have.key("Quantity").equals(2) set(cached_methods["Items"]).should.equal({"HEAD", "GET"}) default_cache.should.have.key("SmoothStreaming").equals(False) default_cache.should.have.key("Compress").equals(True) default_cache.should.have.key("LambdaFunctionAssociations").equals({"Quantity": 0}) default_cache.should.have.key("FunctionAssociations").equals({"Quantity": 0}) default_cache.should.have.key("FieldLevelEncryptionId").equals("") default_cache.should.have.key("CachePolicyId") config.should.have.key("CacheBehaviors").equals({"Quantity": 0}) config.should.have.key("CustomErrorResponses").equals({"Quantity": 0}) config.should.have.key("Comment").equals( "an optional comment that's not actually optional" ) config.should.have.key("Logging") logging = config["Logging"] logging.should.have.key("Enabled").equals(False) logging.should.have.key("IncludeCookies").equals(False) logging.should.have.key("Bucket").equals("") logging.should.have.key("Prefix").equals("") config.should.have.key("PriceClass").equals("PriceClass_All") config.should.have.key("Enabled").equals(False) config.should.have.key("WebACLId") config.should.have.key("HttpVersion").equals("http2") config.should.have.key("IsIPV6Enabled").equals(True) config.should.have.key("ViewerCertificate") cert = config["ViewerCertificate"] cert.should.have.key("CloudFrontDefaultCertificate").equals(True) cert.should.have.key("MinimumProtocolVersion").equals("TLSv1") cert.should.have.key("CertificateSource").equals("cloudfront") config.should.have.key("Restrictions") config["Restrictions"].should.have.key("GeoRestriction") restriction = config["Restrictions"]["GeoRestriction"] restriction.should.have.key("RestrictionType").equals("none") restriction.should.have.key("Quantity").equals(0) config.should.have.key("WebACLId") config.should.have.key("WebACLId").equals("")