# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import pytest
from tests import unittest

from botocore import regions
from botocore.exceptions import NoRegionError, EndpointVariantError


class TestEndpointResolver(unittest.TestCase):
    def _template(self):
        return {
            'partitions': [
                {
                    'partition': 'aws',
                    'dnsSuffix': 'amazonaws.com',
                    'regionRegex': r'^(us|eu)\-\w+$',
                    'defaults': {
                        'hostname': '{service}.{region}.{dnsSuffix}',
                        'variants': [
                            {
                                'hostname': '{service}-fips.{region}.{dnsSuffix}',
                                'tags': ['fips']
                            },
                            {
                                'dnsSuffix': 'api.aws',
                                'hostname': '{service}.{region}.{dnsSuffix}',
                                'tags': ['dualstack']
                            },
                            {
                                'dnsSuffix': 'api.aws',
                                'hostname': '{service}-fips.{region}.{dnsSuffix}',
                                'tags': ['dualstack', 'fips']
                            },
                        ]
                    },
                    'regions': {
                        'us-foo': {'regionName': 'a'},
                        'us-bar': {'regionName': 'b'},
                        'eu-baz': {'regionName': 'd'}
                    },
                    'services': {
                        'ec2': {
                            'defaults': {
                                'protocols': ['http', 'https'],
                                'variants': [
                                    {
                                        'dnsSuffix': 'api.aws',
                                        'hostname': 'api.ec2.{region}.{dnsSuffix}',
                                        'tags': ['dualstack']
                                    }
                                ]
                            },
                            'endpoints': {
                                'us-foo': {
                                    'hostname': 'ec2.us-foo.amazonaws.com',
                                    'variants': [
                                        {
                                            'dnsSuffix': 'api.aws',
                                            'hostname': 'ec2.foo.{dnsSuffix}',
                                            'tags': ['dualstack']
                                        },
                                        {
                                            'hostname': 'ec2-fips.foo.amazonaws.com',
                                            'tags': ['fips']
                                        },
                                        {
                                            'hostname': 'ec2-fips.foo.api.aws',
                                            'tags': ['fips', 'dualstack']
                                        },
                                    ]
                                },
                                'us-bar': {},
                                'us-dep': {
                                    'deprecated': True,
                                },
                                'us-fizz': {
                                    'credentialScope': {
                                        'region': 'us-fizz'
                                    },
                                    'hostname': 'ec2.us-fizz.amazonaws.com',
                                    'variants': [
                                        {
                                            'hostname': 'ec2.fizz.api.aws',
                                            'tags': ['dualstack']
                                        }
                                    ]
                                },
                                'eu-baz': {},
                                'd': {}
                            },
                        },
                        's3': {
                            'defaults': {
                                'sslCommonName': '{service}.{region}.{dnsSuffix}',
                                'variants': [
                                    {
                                        'hostname': 's3.dualstack.{region}.{dnsSuffix}',
                                        'tags': ['dualstack']
                                    },
                                    {
                                        'hostname': 's3-fips.{region}.{dnsSuffix}',
                                        'tags': ['fips']
                                    },
                                    {
                                        'hostname': 's3-fips.dualstack.{region}.{dnsSuffix}',
                                        'tags': ['dualstack', 'fips']
                                    }
                                ]
                            },
                            'endpoints': {
                                'us-foo': {
                                    'sslCommonName': \
                                        '{region}.{service}.{dnsSuffix}'
                                },
                                'us-bar': {},
                                'us-fizz': {
                                    'hostname': 's3.api.us-fizz.amazonaws.com',
                                    'variants': [
                                        {
                                            'tags': ['dualstack']
                                        },
                                        {
                                            'tags': ['fips']
                                        }
                                    ]
                                },
                                'eu-baz': {'hostname': 'foo'}
                            }
                        },
                        'not-regionalized': {
                            'isRegionalized': False,
                            'partitionEndpoint': 'aws',
                            'endpoints': {
                                'aws': {'hostname': 'not-regionalized'},
                                'us-foo': {},
                                'eu-baz': {}
                            }
                        },
                        'non-partition': {
                            'partitionEndpoint': 'aws',
                            'endpoints': {
                                'aws': {'hostname': 'host'},
                                'us-foo': {}
                            }
                        },
                        'merge': {
                            'defaults': {
                                'signatureVersions': ['v2'],
                                'protocols': ['http']
                            },
                            'endpoints': {
                                'us-foo': {'signatureVersions': ['v4']},
                                'us-bar': {'protocols': ['https']}
                            }
                        }
                    }
                },
                {
                    'partition': 'foo',
                    'dnsSuffix': 'foo.com',
                    'regionRegex': r'^(foo)\-\w+$',
                    'defaults': {
                        'hostname': '{service}.{region}.{dnsSuffix}',
                        'protocols': ['http'],
                        'foo': 'bar',
                    },
                    'regions': {
                        'foo-1': {'regionName': '1'},
                        'foo-2': {'regionName': '2'},
                        'foo-3': {'regionName': '3'}
                    },
                    'services': {
                        'ec2': {
                            'endpoints': {
                                'foo-1': {
                                    'foo': 'baz'
                                },
                                'foo-2': {},
                                'foo-3': {}
                            }
                        }
                    }
                },
                {
                    'partition': 'aws-iso',
                    'dnsSuffix': 'amazonaws.com',
                    'defaults': {
                        'hostname': '{service}.{region}.{dnsSuffix}',
                        'protocols': ['http'],
                    },
                    'regions': {
                        'foo-1': {'regionName': '1'},
                        'foo-2': {'regionName': '2'},
                        'foo-3': {'regionName': '3'}
                    },
                    'services': {
                        'ec2': {
                            'endpoints': {
                                'foo-1': {
                                    'foo': 'baz'
                                },
                                'foo-2': {},
                                'foo-3': {}
                            }
                        }
                    }
                }
            ]
        }

    def test_ensures_region_is_not_none(self):
        with self.assertRaises(NoRegionError):
            resolver = regions.EndpointResolver(self._template())
            resolver.construct_endpoint('foo', None)

    def test_ensures_required_keys_present(self):
        with self.assertRaises(ValueError):
            regions.EndpointResolver({})

    def test_returns_empty_list_when_listing_for_different_partition(self):
        resolver = regions.EndpointResolver(self._template())
        self.assertEqual([], resolver.get_available_endpoints('ec2', 'bar'))

    def test_returns_empty_list_when_no_service_found(self):
        resolver = regions.EndpointResolver(self._template())
        self.assertEqual([], resolver.get_available_endpoints('what?'))

    def test_gets_endpoint_names(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.get_available_endpoints(
            'ec2', allow_non_regional=True)
        self.assertEqual(['d', 'eu-baz', 'us-bar', 'us-dep',
                          'us-fizz', 'us-foo'],
                         sorted(result))

    def test_gets_endpoint_names_for_partition(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.get_available_endpoints(
            'ec2', allow_non_regional=True, partition_name='foo')
        self.assertEqual(['foo-1', 'foo-2', 'foo-3'], sorted(result))

    def test_list_regional_endpoints_only(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.get_available_endpoints(
            'ec2', allow_non_regional=False)
        self.assertEqual(['eu-baz', 'us-bar', 'us-foo'], sorted(result))

    def test_returns_none_when_no_match(self):
        resolver = regions.EndpointResolver(self._template())
        self.assertIsNone(resolver.construct_endpoint('foo', 'baz'))

    def test_constructs_regionalized_endpoints_for_exact_matches(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('not-regionalized', 'eu-baz')
        self.assertEqual('not-regionalized.eu-baz.amazonaws.com',
                          result['hostname'])
        self.assertEqual('aws', result['partition'])
        self.assertEqual('eu-baz', result['endpointName'])

    def test_constructs_partition_endpoints_for_real_partition_region(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('not-regionalized', 'us-bar')
        self.assertEqual('not-regionalized', result['hostname'])
        self.assertEqual('aws', result['partition'])
        self.assertEqual('aws', result['endpointName'])

    def test_constructs_partition_endpoints_for_regex_match(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('not-regionalized', 'us-abc')
        self.assertEqual('not-regionalized', result['hostname'])

    def test_constructs_endpoints_for_regionalized_regex_match(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('s3', 'us-abc')
        self.assertEqual('s3.us-abc.amazonaws.com', result['hostname'])

    def test_constructs_endpoints_for_unknown_service_but_known_region(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('unknown', 'us-foo')
        self.assertEqual('unknown.us-foo.amazonaws.com', result['hostname'])

    def test_merges_service_keys(self):
        resolver = regions.EndpointResolver(self._template())
        us_foo = resolver.construct_endpoint('merge', 'us-foo')
        us_bar = resolver.construct_endpoint('merge', 'us-bar')
        self.assertEqual(['http'], us_foo['protocols'])
        self.assertEqual(['v4'], us_foo['signatureVersions'])
        self.assertEqual(['https'], us_bar['protocols'])
        self.assertEqual(['v2'], us_bar['signatureVersions'])

    def test_merges_partition_default_keys_with_no_overwrite(self):
        resolver = regions.EndpointResolver(self._template())
        resolved = resolver.construct_endpoint('ec2', 'foo-1')
        self.assertEqual('baz', resolved['foo'])
        self.assertEqual(['http'], resolved['protocols'])

    def test_merges_partition_default_keys_with_overwrite(self):
        resolver = regions.EndpointResolver(self._template())
        resolved = resolver.construct_endpoint('ec2', 'foo-2')
        self.assertEqual('bar', resolved['foo'])
        self.assertEqual(['http'], resolved['protocols'])

    def test_gives_hostname_and_common_name_unaltered(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('s3', 'eu-baz')
        self.assertEqual('s3.eu-baz.amazonaws.com', result['sslCommonName'])
        self.assertEqual('foo', result['hostname'])

    def tests_uses_partition_endpoint_when_no_region_provided(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('not-regionalized')
        self.assertEqual('not-regionalized', result['hostname'])
        self.assertEqual('aws', result['endpointName'])

    def test_returns_dns_suffix_if_available(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('not-regionalized')
        self.assertEqual(result['dnsSuffix'], 'amazonaws.com')

    def test_construct_dualstack_from_endpoint_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('ec2', 'us-foo',
                                             use_dualstack_endpoint=True)
        self.assertEqual(result['hostname'], 'ec2.foo.api.aws')
        self.assertEqual(result['dnsSuffix'], 'api.aws')

    def test_construct_dualstack_endpoint_from_service_default_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('ec2', 'us-bar',
                                             use_dualstack_endpoint=True)
        self.assertEqual(result['hostname'], 'api.ec2.us-bar.api.aws')
        self.assertEqual(result['dnsSuffix'], 'api.aws')

    def test_construct_dualstack_endpoint_from_partition_default_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('dynamodb', 'us-bar',
                                             use_dualstack_endpoint=True)
        self.assertEqual(result['hostname'], 'dynamodb.us-bar.api.aws')
        self.assertEqual(result['dnsSuffix'], 'api.aws')

    def test_constructs_dualstack_endpoint_no_hostname_in_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('s3', 'us-fizz',
                                             use_dualstack_endpoint=True)
        self.assertEqual('s3.dualstack.us-fizz.api.aws',
                         result['hostname'])

    def test_constructs_endpoint_dualstack_no_variant_dns_suffix(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('s3', 'us-bar',
                                             use_dualstack_endpoint=True)
        self.assertEqual('s3.dualstack.us-bar.api.aws',
                         result['hostname'])

    def test_construct_dualstack_endpoint_iso_partition_raise_exception(self):
        with self.assertRaises(EndpointVariantError):
            resolver = regions.EndpointResolver(self._template())
            resolver.construct_endpoint('foo', 'foo-1', 'aws-iso',
                                        use_dualstack_endpoint=True)

    def test_get_partition_dns_suffix_no_tags(self):
        resolver = regions.EndpointResolver(self._template())
        self.assertEqual(resolver.get_partition_dns_suffix('aws'),
                         'amazonaws.com')

    def test_get_partition_dualstack_dns_suffix(self):
        resolver = regions.EndpointResolver(self._template())
        self.assertEqual(resolver.get_partition_dns_suffix(
            'aws', ['dualstack']), 'api.aws')

    def test_get_partition_dualstack_dns_suffix_does_not_exist(self):
        resolver = regions.EndpointResolver(self._template())
        self.assertIsNone(resolver.get_partition_dns_suffix(
            'foo', ['dualstack']))

    def test_get_available_fips_endpoints(self):
        resolver = regions.EndpointResolver(self._template())
        fips_endpoints = resolver.get_available_endpoints(
            'ec2', endpoint_variant_tags=['fips'])
        self.assertEqual(fips_endpoints, ['us-foo'])

    def test_get_available_dualstack_endpoints(self):
        resolver = regions.EndpointResolver(self._template())
        dualstack_endpoints = resolver.get_available_endpoints(
            'ec2', endpoint_variant_tags=['dualstack'])
        self.assertEqual(dualstack_endpoints, ['us-foo'])

    def test_get_available_fips_and_dualstack_endpoints(self):
        resolver = regions.EndpointResolver(self._template())
        fips_and_dualstack_endpoints = resolver.get_available_endpoints(
            'ec2', endpoint_variant_tags=['fips', 'dualstack'])
        self.assertEqual(fips_and_dualstack_endpoints, ['us-foo'])

    def test_get_available_fips_endpoints_none(self):
        resolver = regions.EndpointResolver(self._template())
        fips_endpoints = resolver.get_available_endpoints(
            'ec2', 'foo', endpoint_variant_tags=['fips'])
        self.assertEqual(fips_endpoints, [])

    def test_get_available_dualstack_endpoints_none(self):
        resolver = regions.EndpointResolver(self._template())
        dualstack_endpoints = resolver.get_available_endpoints(
            'ec2', 'foo', endpoint_variant_tags=['dualstack'])
        self.assertEqual(dualstack_endpoints, [])

    def test_get_available_fips_and_dualstack_endpoints_none(self):
        resolver = regions.EndpointResolver(self._template())
        fips_and_dualstack_endpoints = resolver.get_available_endpoints(
            'ec2', 'foo', endpoint_variant_tags=['fips', 'dualstack'])
        self.assertEqual(fips_and_dualstack_endpoints, [])

    def test_construct_deprecated_endpoint_raises_warning(self):
        resolver = regions.EndpointResolver(self._template())
        with self.assertLogs('botocore.regions', level='WARNING') as log:
            result = resolver.construct_endpoint('ec2', 'us-dep',
                                                 use_fips_endpoint=True,
                                                 )
            self.assertIn('deprecated endpoint', log.output[0])
            self.assertEqual(result['hostname'], 'ec2-fips.us-dep.amazonaws.com')
            self.assertEqual(result['dnsSuffix'], 'amazonaws.com')

    def test_construct_fips_from_endpoint_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('ec2', 'us-foo',
                                             use_fips_endpoint=True)
        self.assertEqual(result['hostname'], 'ec2-fips.foo.amazonaws.com')
        self.assertEqual(result['dnsSuffix'], 'amazonaws.com')

    def test_construct_fips_endpoint_from_service_default_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('ec2', 'us-bar',
                                             use_fips_endpoint=True)
        self.assertEqual(result['hostname'], 'ec2-fips.us-bar.amazonaws.com')
        self.assertEqual(result['dnsSuffix'], 'amazonaws.com')

    def test_construct_fips_endpoint_from_partition_default_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('dynamodb', 'us-bar',
                                             use_fips_endpoint=True)
        self.assertEqual(result['hostname'],
                         'dynamodb-fips.us-bar.amazonaws.com')
        self.assertEqual(result['dnsSuffix'], 'amazonaws.com')

    def test_constructs_fips_endpoint_no_hostname_in_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('s3', 'us-fizz',
                                             use_fips_endpoint=True)
        self.assertEqual('s3-fips.us-fizz.amazonaws.com', result['hostname'])

    def test_construct_dualstack_and_fips_from_endpoint_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('ec2', 'us-foo',
                                             use_dualstack_endpoint=True,
                                             use_fips_endpoint=True)
        self.assertEqual(result['hostname'], 'ec2-fips.foo.api.aws')
        self.assertEqual(result['dnsSuffix'], 'api.aws')

    def test_construct_dualstack_and_fips_endpoint_from_service_default_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('ec2', 'us-bar',
                                             use_dualstack_endpoint=True,
                                             use_fips_endpoint=True)
        self.assertEqual(result['hostname'], 'ec2-fips.us-bar.api.aws')
        self.assertEqual(result['dnsSuffix'], 'api.aws')

    def test_construct_dualstack_and_fips_endpoint_from_partition_default_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('dynamodb', 'us-bar',
                                             use_dualstack_endpoint=True,
                                             use_fips_endpoint=True)
        self.assertEqual(result['hostname'], 'dynamodb-fips.us-bar.api.aws')
        self.assertEqual(result['dnsSuffix'], 'api.aws')

    def test_constructs_dualstack_and_fips_endpoint_no_hostname_in_variant(self):
        resolver = regions.EndpointResolver(self._template())
        result = resolver.construct_endpoint('s3', 'us-fizz',
                                             use_dualstack_endpoint=True,
                                             use_fips_endpoint=True)
        self.assertEqual('s3-fips.dualstack.us-fizz.api.aws',
                         result['hostname'])

    def test_construct_fips_endpoint_no_variant_raise_exception(self):
        with self.assertRaises(EndpointVariantError):
            resolver = regions.EndpointResolver(self._template())
            resolver.construct_endpoint('ec2', 'foo-1', 'foo',
                                        use_fips_endpoint=True)

    def test_construct_dualstack_endpoint_no_variant_raise_exception(self):
        with self.assertRaises(EndpointVariantError):
            resolver = regions.EndpointResolver(self._template())
            resolver.construct_endpoint('ec2', 'foo-1', 'foo',
                                        use_dualstack_endpoint=True)

    def test_construct_dualstack_and_fips_endpoint_no_variant_raise_exception(self):
        with self.assertRaises(EndpointVariantError):
            resolver = regions.EndpointResolver(self._template())
            resolver.construct_endpoint('ec2', 'foo-1', 'foo',
                                        use_dualstack_endpoint=True,
                                        use_fips_endpoint=True)


def _variant_test_definitions():
    return [
        {
            "service": "default-pattern-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "default-pattern-service.us-west-2.amazonaws.com"
        },
        {
            "service": "default-pattern-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": False,
            "endpoint": "default-pattern-service-fips.us-west-2.amazonaws.com"
        },
        {
            "service": "default-pattern-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "default-pattern-service.af-south-1.amazonaws.com"
        },
        {
            "service": "default-pattern-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": False,
            "endpoint": "default-pattern-service-fips.af-south-1.amazonaws.com"
        },
        {
            "service": "global-service",
            "region": "aws-global",
            "fips": False,
            "dualstack": False,
            "endpoint": "global-service.amazonaws.com"
        },
        {
            "service": "global-service",
            "region": "aws-global",
            "fips": True,
            "dualstack": False,
            "endpoint": "global-service-fips.amazonaws.com"
        },
        {
            "service": "global-service",
            "region": "foo",
            "fips": False,
            "dualstack": False,
            "endpoint": "global-service.amazonaws.com"
        },
        {
            "service": "global-service",
            "region": "foo",
            "fips": True,
            "dualstack": False,
            "endpoint": "global-service-fips.amazonaws.com"
        },
        {
            "service": "override-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.override-variant-service.us-west-2.new.dns.suffix"
        },
        {
            "service": "override-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-variant-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.override-variant-service.af-south-1.new.dns.suffix"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-dns-suffix-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": False,
            "endpoint": "override-variant-dns-suffix-service-fips.us-west-2.new.dns.suffix"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-dns-suffix-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": False,
            "endpoint": "override-variant-dns-suffix-service-fips.af-south-1.new.dns.suffix"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-hostname-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.override-variant-hostname-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-hostname-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.override-variant-hostname-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-endpoint-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.override-endpoint-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-endpoint-variant-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": False,
            "endpoint": "override-endpoint-variant-service-fips.af-south-1.amazonaws.com"
        },
        {
            "service": "default-pattern-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "default-pattern-service.us-west-2.amazonaws.com"
        },
        {
            "service": "default-pattern-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": True,
            "endpoint": "default-pattern-service.us-west-2.api.aws"
        },
        {
            "service": "default-pattern-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "default-pattern-service.af-south-1.amazonaws.com"
        },
        {
            "service": "default-pattern-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": True,
            "endpoint": "default-pattern-service.af-south-1.api.aws"
        },
        {
            "service": "global-service",
            "region": "aws-global",
            "fips": False,
            "dualstack": False,
            "endpoint": "global-service.amazonaws.com"
        },
        {
            "service": "global-service",
            "region": "aws-global",
            "fips": False,
            "dualstack": True,
            "endpoint": "global-service.api.aws"
        },
        {
            "service": "global-service",
            "region": "foo",
            "fips": False,
            "dualstack": False,
            "endpoint": "global-service.amazonaws.com"
        },
        {
            "service": "global-service",
            "region": "foo",
            "fips": False,
            "dualstack": True,
            "endpoint": "global-service.api.aws"
        },
        {
            "service": "override-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-variant-service.dualstack.us-west-2.new.dns.suffix"
        },
        {
            "service": "override-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-variant-service.dualstack.af-south-1.new.dns.suffix"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-dns-suffix-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-variant-dns-suffix-service.us-west-2.new.dns.suffix"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-dns-suffix-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-variant-dns-suffix-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-variant-dns-suffix-service.af-south-1.new.dns.suffix"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-hostname-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-variant-hostname-service.dualstack.us-west-2.api.aws"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-variant-hostname-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-variant-hostname-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-variant-hostname-service.dualstack.af-south-1.api.aws"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-endpoint-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-endpoint-variant-service.dualstack.us-west-2.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "override-endpoint-variant-service.af-south-1.amazonaws.com"
        },
        {
            "service": "override-endpoint-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": True,
            "endpoint": "override-endpoint-variant-service.af-south-1.api.aws"
        },
        {
            "service": "multi-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": False,
            "endpoint": "multi-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "multi-variant-service",
            "region": "us-west-2",
            "fips": False,
            "dualstack": True,
            "endpoint": "multi-variant-service.dualstack.us-west-2.api.aws"
        },
        {
            "service": "multi-variant-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.multi-variant-service.us-west-2.amazonaws.com"
        },
        {
            "service": "multi-variant-service",
            "region": "us-west-2",
            "fips": True,
            "dualstack": True,
            "endpoint": "fips.multi-variant-service.dualstack.us-west-2.new.dns.suffix"
        },
        {
            "service": "multi-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": False,
            "endpoint": "multi-variant-service.af-south-1.amazonaws.com"
        },
        {
            "service": "multi-variant-service",
            "region": "af-south-1",
            "fips": False,
            "dualstack": True,
            "endpoint": "multi-variant-service.dualstack.af-south-1.api.aws"
        },
        {
            "service": "multi-variant-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": False,
            "endpoint": "fips.multi-variant-service.af-south-1.amazonaws.com"
        },
        {
            "service": "multi-variant-service",
            "region": "af-south-1",
            "fips": True,
            "dualstack": True,
            "endpoint": "fips.multi-variant-service.dualstack.af-south-1.new.dns.suffix"
        }
    ]


def _modeled_variants_template():
    return {
        "partitions" : [
            {
                "defaults" : {
                    "hostname" : "{service}.{region}.{dnsSuffix}",
                    "protocols" : ["https"],
                    "signatureVersions" : ["v4"],
                    "variants" : [
                        {
                            "dnsSuffix" : "amazonaws.com",
                            "hostname" : "{service}-fips.{region}.{dnsSuffix}",
                            "tags" : ["fips"]
                        },
                        {
                            "dnsSuffix" : "api.aws",
                            "hostname" : "{service}.{region}.{dnsSuffix}",
                            "tags" : ["dualstack"]
                        },
                        {
                            "dnsSuffix" : "api.aws",
                            "hostname" : "{service}-fips.{region}.{dnsSuffix}",
                            "tags" : ["dualstack", "fips"]
                        }
                    ]
                },
                "dnsSuffix" : "amazonaws.com",
                "partition" : "aws",
                "regionRegex" : "^(us|eu|ap|sa|ca|me|af)\\-\\w+\\-\\d+$",
                "regions" : {
                    "af-south-1" : {
                        "description" : "Africa (Cape Town)"
                    },
                    "us-west-2" : {
                        "description" : "US West (Oregon)"
                    }
                },
                "services" : {
                    "default-pattern-service" : {
                        "endpoints" : {
                            "af-south-1" : {},
                            "us-west-2" : {
                                "variants" : [
                                    {
                                        "hostname" : "default-pattern-service-fips.us-west-2.amazonaws.com",
                                        "tags" : ["fips"]
                                    },
                                    {
                                        "hostname" : "default-pattern-service.us-west-2.api.aws",
                                        "tags" : ["dualstack"]
                                    }
                                ]
                            }
                        }
                    },
                    "global-service" : {
                        "endpoints" : {
                            "aws-global" : {
                                "credentialScope" : {
                                    "region" : "us-east-1"
                                },
                                "hostname" : "global-service.amazonaws.com",
                                "variants" : [
                                    {
                                        "hostname" : "global-service-fips.amazonaws.com",
                                        "tags" : ["fips"]
                                    },
                                    {
                                        "hostname" : "global-service.api.aws",
                                        "tags" : ["dualstack"]
                                    }
                                ]
                            }
                        },
                        "isRegionalized" : False,
                        "partitionEndpoint" : "aws-global"
                    },
                    "override-variant-service" : {
                        "defaults" : {
                            "variants" : [
                                {
                                    "hostname" : "fips.{service}.{region}.{dnsSuffix}",
                                    "dnsSuffix" : "new.dns.suffix",
                                    "tags" : ["fips"]
                                },
                                {
                                    "hostname" : "{service}.dualstack.{region}.{dnsSuffix}",
                                    "dnsSuffix" : "new.dns.suffix",
                                    "tags" : ["dualstack"]
                                }
                            ]
                        },
                        "endpoints" : {
                            "af-south-1" : {},
                            "us-west-2" : {
                                "variants" : [
                                    {
                                        "hostname" : "fips.override-variant-service.us-west-2.new.dns.suffix",
                                        "tags" : ["fips"]
                                    },
                                    {
                                        "hostname" : "override-variant-service.dualstack.us-west-2.new.dns.suffix",
                                        "tags" : ["dualstack"]
                                    }
                                ]
                            }
                        }
                    },
                    "override-variant-dns-suffix-service" : {
                        "defaults" : {
                            "variants" : [
                                {
                                    "dnsSuffix" : "new.dns.suffix",
                                    "tags" : ["fips"]
                                },
                                {
                                    "dnsSuffix" : "new.dns.suffix",
                                    "tags" : ["dualstack"]
                                }
                            ]
                        },
                        "endpoints" : {
                            "af-south-1" : {},
                            "us-west-2" : {
                                "variants" : [
                                    {
                                        "hostname" : "override-variant-dns-suffix-service-fips.us-west-2.new.dns.suffix",
                                        "tags" : ["fips"]
                                    },
                                    {
                                        "hostname" : "override-variant-dns-suffix-service.us-west-2.new.dns.suffix",
                                        "tags" : ["dualstack"]
                                    }
                                ]
                            }
                        }
                    },
                    "override-variant-hostname-service" : {
                        "defaults" : {
                            "variants" : [
                                {
                                    "hostname" : "fips.{service}.{region}.{dnsSuffix}",
                                    "tags" : ["fips"]
                                },
                                {
                                    "hostname" : "{service}.dualstack.{region}.{dnsSuffix}",
                                    "tags" : ["dualstack"]
                                }
                            ]
                        },
                        "endpoints" : {
                            "af-south-1" : {},
                            "us-west-2" : {
                                "variants" : [
                                    {
                                        "hostname" : "fips.override-variant-hostname-service.us-west-2.amazonaws.com",
                                        "tags" : ["fips"]
                                    },
                                    {
                                        "hostname" : "override-variant-hostname-service.dualstack.us-west-2.api.aws",
                                        "tags" : ["dualstack"]
                                    }
                                ]
                            }
                        }
                    },
                    "override-endpoint-variant-service" : {
                        "endpoints" : {
                            "af-south-1" : {},
                            "us-west-2" : {
                                "variants" : [
                                    {
                                        "hostname" : "fips.override-endpoint-variant-service.us-west-2.amazonaws.com",
                                        "tags" : ["fips"]
                                    },
                                    {
                                        "hostname" : "override-endpoint-variant-service.dualstack.us-west-2.amazonaws.com",
                                        "tags" : ["dualstack"]
                                    }
                                ]
                            }
                        }
                    },
                    "multi-variant-service" : {
                        "defaults" : {
                            "variants" : [
                                {
                                    "hostname" : "fips.{service}.{region}.{dnsSuffix}",
                                    "tags" : ["fips"]
                                },
                                {
                                    "hostname" : "{service}.dualstack.{region}.{dnsSuffix}",
                                    "tags" : ["dualstack"]
                                },
                                {
                                    "dnsSuffix" : "new.dns.suffix",
                                    "hostname" : "fips.{service}.dualstack.{region}.{dnsSuffix}",
                                    "tags" : ["fips", "dualstack"]
                                }
                            ]
                        },
                        "endpoints" : {
                            "af-south-1" : {
                                "deprecated" : True
                            },
                            "us-west-2" : {
                                "variants" : [
                                    {
                                        "hostname" : "fips.multi-variant-service.dualstack.us-west-2.new.dns.suffix",
                                        "tags" : ["fips", "dualstack"]
                                    }
                                ]
                            }
                        }
                    }
                }
            },
            {
                "defaults": {
                    "hostname": "{service}.{region}.{dnsSuffix}",
                    "protocols": ["https"],
                    "signatureVersions": ["v4"]
                },
                "dnsSuffix": "c2s.ic.gov",
                "partition": "aws-iso",
                "regionRegex": "^us\\-iso\\-\\w+\\-\\d+$",
                "regions": {
                    "us-iso-east-1": {
                        "description": "US ISO East"
                    }
                },
                "services": {
                    "some-service": {
                        "endpoints" : {
                            "us-iso-east-1": {}
                        }
                    }
                }
            }
        ],
        "version": 3
    }


@pytest.mark.parametrize("test_case", _variant_test_definitions())
def test_modeled_variants(test_case):
    _verify_expected_endpoint(**test_case)


def _verify_expected_endpoint(service, region, fips, dualstack,
                              endpoint):
    resolver = regions.EndpointResolver(_modeled_variants_template())
    resolved = resolver.construct_endpoint(
        service, region, use_dualstack_endpoint=dualstack,
        use_fips_endpoint=fips
    )
    # If we can't resolve the region, we attempt to get a
    # global endpoint.
    if not resolved:
        resolved = resolver.construct_endpoint(
            service, region, partition_name='aws',
            use_dualstack_endpoint=dualstack,
            use_fips_endpoint=fips
        )
    assert resolved['hostname'] == endpoint


def test_additional_endpoint_data_exists_with_variants():
    resolver = regions.EndpointResolver(_modeled_variants_template())
    resolved = resolver.construct_endpoint(
        'global-service', 'aws-global', use_fips_endpoint=True,
    )
    assert resolved['credentialScope'] == {'region': 'us-east-1'}
