Ejemplo n.º 1
0
    def setup_loader_modules(self):
        class DBusException(BaseException):
            get_dbus_name = "foo"

        dbus_mock = MagicMock()
        dbus_mock.configure_mock(DBusException=DBusException)
        return {snapper: {"dbus": dbus_mock, "snapper": MagicMock()}}
Ejemplo n.º 2
0
    def setup_loader_modules(self):
        class DBusException(BaseException):
            get_dbus_name = 'foo'

        dbus_mock = MagicMock()
        dbus_mock.configure_mock(DBusException=DBusException)
        return {snapper: {'dbus': dbus_mock, 'snapper': MagicMock()}}
Ejemplo n.º 3
0
class Boto3ElasticsearchTestCase(TestCase, LoaderModuleMockMixin):
    '''
    TestCase for salt.modules.boto3_elasticsearch module
    '''
    conn = None

    def setup_loader_modules(self):
        self.opts = salt.config.DEFAULT_MINION_OPTS.copy()
        utils = salt.loader.utils(
            self.opts,
            whitelist=['boto3', 'args', 'systemd', 'path', 'platform'],
            context={})
        return {boto3_elasticsearch: {'__utils__': utils}}

    def setUp(self):
        super(Boto3ElasticsearchTestCase, self).setUp()
        boto3_elasticsearch.__init__(self.opts)
        del self.opts

        # Set up MagicMock to replace the boto3 session
        # connections keep getting cached from prior tests, can't find the
        # correct context object to clear it. So randomize the cache key, to prevent any
        # cache hits
        CONN_PARAMETERS['key'] = ''.join(
            random.choice(string.ascii_lowercase + string.digits)
            for _ in range(50))

        self.conn = MagicMock()
        self.addCleanup(delattr, self, 'conn')
        self.patcher = patch('boto3.session.Session')
        self.addCleanup(self.patcher.stop)
        self.addCleanup(delattr, self, 'patcher')
        mock_session = self.patcher.start()
        session_instance = mock_session.return_value
        session_instance.configure_mock(client=MagicMock(
            return_value=self.conn))
        self.paginator = MagicMock()
        self.addCleanup(delattr, self, 'paginator')
        self.conn.configure_mock(get_paginator=MagicMock(
            return_value=self.paginator))

    def test_describe_elasticsearch_domain_positive(self):
        '''
        Test that when describing a domain when the domain actually exists,
        the .exists method returns a dict with 'result': True
        and 'response' with the domain status information.
        '''
        # The patch below is not neccesary per se,
        # as .exists returns positive as long as no exception is raised.
        with patch.object(self.conn,
                          'describe_elasticsearch_domain',
                          return_value={'DomainStatus': DOMAIN_RET}):
            self.assertEqual(
                boto3_elasticsearch.describe_elasticsearch_domain(
                    domain_name='testdomain', **CONN_PARAMETERS), {
                        'result': True,
                        'response': DOMAIN_RET
                    })

    def test_describe_elasticsearch_domain_error(self):
        '''
        Test that when describing a domain when the domain does not exist,
        the .exists method returns a dict with 'result': False
        and 'error' with boto's ResourceNotFoundException.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domain',
                          side_effect=NOT_FOUND_ERROR):
            result = boto3_elasticsearch.describe_elasticsearch_domain(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format('ResourceNotFoundException', 'msg'))
            self.assertFalse(result['result'])

    def test_create_elasticsearch_domain_positive(self):
        '''
        Test that when creating a domain, and it succeeds,
        the .create method returns a dict with 'result': True
        and 'response' with the newly created domain's status information.
        '''
        with patch.object(self.conn,
                          'create_elasticsearch_domain',
                          return_value={'DomainStatus': DOMAIN_RET}):
            kwargs = {
                'elasticsearch_version':
                DOMAIN_RET['ElasticsearchVersion'],
                'elasticsearch_cluster_config':
                DOMAIN_RET['ElasticsearchClusterConfig'],
                'ebs_options':
                DOMAIN_RET['EBSOptions'],
                'access_policies':
                DOMAIN_RET['AccessPolicies'],
                'snapshot_options':
                DOMAIN_RET['SnapshotOptions'],
                'vpc_options':
                DOMAIN_RET['VPCOptions'],
                'cognito_options':
                DOMAIN_RET['CognitoOptions'],
                'encryption_at_rest_options':
                DOMAIN_RET['EncryptionAtRestOptions'],
                'advanced_options':
                DOMAIN_RET['AdvancedOptions'],
            }
            kwargs.update(CONN_PARAMETERS)
            self.assertEqual(
                boto3_elasticsearch.create_elasticsearch_domain(
                    domain_name='testdomain', **kwargs), {
                        'result': True,
                        'response': DOMAIN_RET
                    })

    def test_create_elasticsearch_domain_error(self):
        '''
        Test that when creating a domain, and boto3 returns an error,
        the .create method returns a dict with 'result': False
        and 'error' with the error reported by boto3.
        '''
        with patch.object(self.conn,
                          'create_elasticsearch_domain',
                          side_effect=ClientError(ERROR_CONTENT,
                                                  'create_domain')):
            kwargs = {
                'elasticsearch_version':
                DOMAIN_RET['ElasticsearchVersion'],
                'elasticsearch_cluster_config':
                DOMAIN_RET['ElasticsearchClusterConfig'],
                'ebs_options':
                DOMAIN_RET['EBSOptions'],
                'access_policies':
                DOMAIN_RET['AccessPolicies'],
                'snapshot_options':
                DOMAIN_RET['SnapshotOptions'],
                'vpc_options':
                DOMAIN_RET['VPCOptions'],
                'cognito_options':
                DOMAIN_RET['CognitoOptions'],
                'encryption_at_rest_options':
                DOMAIN_RET['EncryptionAtRestOptions'],
                'advanced_options':
                DOMAIN_RET['AdvancedOptions'],
            }
            kwargs.update(CONN_PARAMETERS)
            result = boto3_elasticsearch.create_elasticsearch_domain(
                'testdomain', **kwargs)
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'create_domain'))

    def test_delete_domain_positive(self):
        '''
        Test that when deleting a domain, and it succeeds,
        the .delete method returns {'result': True}.
        '''
        with patch.object(self.conn, 'delete_elasticsearch_domain'):
            self.assertEqual(
                boto3_elasticsearch.delete_elasticsearch_domain(
                    'testdomain', **CONN_PARAMETERS), {'result': True})

    def test_delete_domain_error(self):
        '''
        Test that when deleting a domain, and boto3 returns an error,
        the .delete method returns {'result': False, 'error' :'the error'}.
        '''
        with patch.object(self.conn,
                          'delete_elasticsearch_domain',
                          side_effect=ClientError(ERROR_CONTENT,
                                                  'delete_domain')):
            result = boto3_elasticsearch.delete_elasticsearch_domain(
                'testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'delete_domain'))

    def test_update_domain_positive(self):
        '''
        Test that when updating a domain succeeds, the .update method returns {'result': True}.
        '''
        with patch.object(self.conn,
                          'update_elasticsearch_domain_config',
                          return_value={'DomainConfig': DOMAIN_RET}):
            kwargs = {
                'elasticsearch_cluster_config':
                DOMAIN_RET['ElasticsearchClusterConfig'],
                'ebs_options':
                DOMAIN_RET['EBSOptions'],
                'snapshot_options':
                DOMAIN_RET['SnapshotOptions'],
                'vpc_options':
                DOMAIN_RET['VPCOptions'],
                'cognito_options':
                DOMAIN_RET['CognitoOptions'],
                'advanced_options':
                DOMAIN_RET['AdvancedOptions'],
                'access_policies':
                DOMAIN_RET['AccessPolicies'],
                'log_publishing_options': {},
            }

            kwargs.update(CONN_PARAMETERS)
            self.assertEqual(
                boto3_elasticsearch.update_elasticsearch_domain_config(
                    'testdomain', **kwargs), {
                        'result': True,
                        'response': DOMAIN_RET
                    })

    def test_update_domain_error(self):
        '''
        Test that when updating a domain fails, and boto3 returns an error,
        the .update method returns the error.
        '''
        with patch.object(self.conn,
                          'update_elasticsearch_domain_config',
                          side_effect=ClientError(ERROR_CONTENT,
                                                  'update_domain')):
            kwargs = {
                'elasticsearch_cluster_config':
                DOMAIN_RET['ElasticsearchClusterConfig'],
                'ebs_options':
                DOMAIN_RET['EBSOptions'],
                'snapshot_options':
                DOMAIN_RET['SnapshotOptions'],
                'vpc_options':
                DOMAIN_RET['VPCOptions'],
                'cognito_options':
                DOMAIN_RET['CognitoOptions'],
                'advanced_options':
                DOMAIN_RET['AdvancedOptions'],
                'access_policies':
                DOMAIN_RET['AccessPolicies'],
                'log_publishing_options': {},
            }
            kwargs.update(CONN_PARAMETERS)
            result = boto3_elasticsearch.update_elasticsearch_domain_config(
                'testdomain', **kwargs)
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'update_domain'))

    def test_add_tags_positive(self):
        '''
        Test that when adding tags is succesful, the .add_tags method returns {'result': True}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domain',
                          return_value={'DomainStatus': DOMAIN_RET}):
            self.assertEqual(
                boto3_elasticsearch.add_tags('testdomain',
                                             tags={
                                                 'foo': 'bar',
                                                 'baz': 'qux'
                                             },
                                             **CONN_PARAMETERS),
                {'result': True})

    def test_add_tags_error(self):
        '''
        Test that when adding tags fails, and boto3 returns an error,
        the .add_tags function returns {'tagged': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'add_tags',
                          side_effect=ClientError(ERROR_CONTENT, 'add_tags')), \
                patch.object(self.conn,
                             'describe_elasticsearch_domain',
                             return_value={'DomainStatus': DOMAIN_RET}):
            result = boto3_elasticsearch.add_tags('testdomain',
                                                  tags={
                                                      'foo': 'bar',
                                                      'baz': 'qux'
                                                  },
                                                  **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'add_tags'))

    def test_remove_tags_positive(self):
        '''
        Test that when removing tags is succesful, the .remove_tags method returns {'tagged': True}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domain',
                          return_value={'DomainStatus': DOMAIN_RET}):
            self.assertEqual(
                boto3_elasticsearch.remove_tags(tag_keys=['foo', 'bar'],
                                                domain_name='testdomain',
                                                **CONN_PARAMETERS),
                {'result': True})

    def test_remove_tag_error(self):
        '''
        Test that when removing tags fails, and boto3 returns an error,
        the .remove_tags method returns {'tagged': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'remove_tags',
                          side_effect=ClientError(ERROR_CONTENT, 'remove_tags')), \
                patch.object(self.conn,
                             'describe_elasticsearch_domain',
                             return_value={'DomainStatus': DOMAIN_RET}):
            result = boto3_elasticsearch.remove_tags(tag_keys=['foo', 'bar'],
                                                     domain_name='testdomain',
                                                     **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'remove_tags'))

    def test_list_tags_positive(self):
        '''
        Test that when listing tags is succesful,
        the .list_tags method returns a dict with key 'tags'.
        Also test that the tags returned are manipulated properly (i.e. transformed
        into a dict with tags).
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domain',
                          return_value={'DomainStatus': DOMAIN_RET}), \
                patch.object(self.conn,
                             'list_tags',
                             return_value={'TagList': [{'Key': 'foo', 'Value': 'bar'}]}):
            result = boto3_elasticsearch.list_tags(domain_name='testdomain',
                                                   **CONN_PARAMETERS)
            self.assertEqual(result, {
                'result': True,
                'response': {
                    'foo': 'bar'
                }
            })

    def test_list_tags_error(self):
        '''
        Test that when listing tags causes boto3 to return an error,
        the .list_tags method returns the error.
        '''
        with patch.object(self.conn,
                          'list_tags',
                          side_effect=ClientError(ERROR_CONTENT, 'list_tags')), \
                patch.object(self.conn,
                             'describe_elasticsearch_domain',
                             return_value={'DomainStatus': DOMAIN_RET}):
            result = boto3_elasticsearch.list_tags(domain_name='testdomain',
                                                   **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'list_tags'))

    def test_cancel_elasticsearch_service_software_update_positive(self):
        '''
        Test that when calling cancel_elasticsearch_service_software_update and
        it is succesful, it returns {'result': True}.
        '''
        retval = {
            'ServiceSoftwareOptions': {
                'CurrentVersion': 'string',
                'NewVersion': 'string',
                'UpdateAvailable': True,
                'Cancellable': True,
                'UpdateStatus': 'ELIGIBLE',
                'Description': 'string',
                'AutomatedUpdateDate': datetime.datetime(2015, 1, 1),
            }
        }
        with patch.object(self.conn,
                          'cancel_elasticsearch_service_software_update',
                          return_value=retval):
            result = boto3_elasticsearch.cancel_elasticsearch_service_software_update(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertEqual(result, {
                'result': True,
            })

    def test_cancel_elasticsearch_service_software_update_error(self):
        '''
        Test that when calling cancel_elasticsearch_service_software_update and
        boto3 returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'cancel_elasticsearch_service_software_update',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'cancel_elasticsearch_service_software_update')):
            result = boto3_elasticsearch.cancel_elasticsearch_service_software_update(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(
                    101, 'cancel_elasticsearch_service_software_update'))

    def test_delete_elasticsearch_service_role_positive(self):
        '''
        Test that when calling delete_elasticsearch_service_role and
        it is succesful, it returns {'result': True}.
        '''
        with patch.object(self.conn,
                          'delete_elasticsearch_service_role',
                          return_value=None):
            result = boto3_elasticsearch.delete_elasticsearch_service_role(
                **CONN_PARAMETERS)
            self.assertEqual(result, {
                'result': True,
            })

    def test_delete_elasticsearch_service_role_error(self):
        '''
        Test that when calling delete_elasticsearch_service_role and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'delete_elasticsearch_service_role',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'delete_elasticsearch_service_role')):
            result = boto3_elasticsearch.delete_elasticsearch_service_role(
                **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101, 'delete_elasticsearch_service_role'))

    def test_describe_elasticsearch_domain_config_positive(self):
        '''
        Test that when calling describe_elasticsearch_domain_config and
        it is succesful, it returns {'result': True}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domain_config',
                          return_value={'DomainConfig': DOMAIN_RET}):
            self.assertEqual(
                boto3_elasticsearch.describe_elasticsearch_domain_config(
                    'testdomain', **CONN_PARAMETERS), {
                        'result': True,
                        'response': DOMAIN_RET
                    })

    def test_describe_elasticsearch_domain_config_error(self):
        '''
        Test that when calling describe_elasticsearch_domain_config and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domain_config',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'describe_elasticsearch_domain_config')):
            result = boto3_elasticsearch.describe_elasticsearch_domain_config(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101,
                                     'describe_elasticsearch_domain_config'))

    def test_describe_elasticsearch_domains_positive(self):
        '''
        Test that when calling describe_elasticsearch_domains and it is succesful,
        it returns {'result': True, 'response': some_data}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domains',
                          return_value={'DomainStatusList': [DOMAIN_RET]}):
            self.assertEqual(
                boto3_elasticsearch.describe_elasticsearch_domains(
                    domain_names=['test_domain'], **CONN_PARAMETERS), {
                        'result': True,
                        'response': [DOMAIN_RET]
                    })

    def test_describe_elasticsearch_domains_error(self):
        '''
        Test that when calling describe_elasticsearch_domains and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_domains',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'describe_elasticsearch_domains')):
            result = boto3_elasticsearch.describe_elasticsearch_domains(
                domain_names=['testdomain'], **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101, 'describe_elasticsearch_domains'))

    def test_describe_elasticsearch_instance_type_limits_positive(self):
        '''
        Test that when calling describe_elasticsearch_instance_type_limits and
        it succeeds, it returns {'result': True, 'response' some_value}.
        '''
        ret_val = {
            'LimitsByRole': {
                'string': {
                    'StorageTypes': [{
                        'StorageTypeName':
                        'string',
                        'StorageSubTypeName':
                        'string',
                        'StorageTypeLimits': [{
                            'LimitName': 'string',
                            'LimitValues': ['string'],
                        }],
                    }],
                    'InstanceLimits': {
                        'InstanceCountLimits': {
                            'MinimumInstanceCount': 123,
                            'MaximumInstanceCount': 123
                        }
                    },
                    'AdditionalLimits': [{
                        'LimitName': 'string',
                        'LimitValues': ['string']
                    }],
                }
            }
        }
        with patch.object(self.conn,
                          'describe_elasticsearch_instance_type_limits',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.
                describe_elasticsearch_instance_type_limits(
                    domain_name='testdomain',
                    instance_type='foo',
                    elasticsearch_version='1.0',
                    **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['LimitsByRole']
                    })

    def test_describe_elasticsearch_instance_type_limits_error(self):
        '''
        Test that when calling describe_elasticsearch_instance_type_limits and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'describe_elasticsearch_instance_type_limits',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'describe_elasticsearch_instance_type_limits')):
            result = boto3_elasticsearch.describe_elasticsearch_instance_type_limits(
                domain_name='testdomain',
                instance_type='foo',
                elasticsearch_version='1.0',
                **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(
                    101, 'describe_elasticsearch_instance_type_limits'))

    def test_describe_reserved_elasticsearch_instance_offerings_positive(self):
        '''
        Test that when calling describe_reserved_elasticsearch_instance_offerings
        and it succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'NextToken':
            'string',
            'ReservedElasticsearchInstanceOfferings': [{
                'ReservedElasticsearchInstanceOfferingId':
                'string',
                'ElasticsearchInstanceType':
                't2.medium.elasticsearch',
                'Duration':
                123,
                'FixedPrice':
                123.0,
                'UsagePrice':
                123.0,
                'CurrencyCode':
                'string',
                'PaymentOption':
                'NO_UPFRONT',
                'RecurringCharges': [{
                    'RecurringChargeAmount': 123.0,
                    'RecurringChargeFrequency': 'string'
                }]
            }]
        }
        with patch.object(self.paginator, 'paginate', return_value=[ret_val]):
            self.assertEqual(
                boto3_elasticsearch.
                describe_reserved_elasticsearch_instance_offerings(
                    reserved_elasticsearch_instance_offering_id='foo',
                    **CONN_PARAMETERS), {
                        'result': True,
                        'response':
                        ret_val['ReservedElasticsearchInstanceOfferings']
                    })

    def test_describe_reserved_elasticsearch_instance_offerings_error(self):
        '''
        Test that when calling describe_reserved_elasticsearch_instance_offerings
        and boto3 returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(
                self.paginator,
                'paginate',
                side_effect=ClientError(
                    ERROR_CONTENT,
                    'describe_reserved_elasticsearch_instance_offerings')):
            result = boto3_elasticsearch.describe_reserved_elasticsearch_instance_offerings(
                reserved_elasticsearch_instance_offering_id='foo',
                **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(
                    101, 'describe_reserved_elasticsearch_instance_offerings'))

    def test_describe_reserved_elasticsearch_instances_positive(self):
        '''
        Test that when calling describe_reserved_elasticsearch_instances and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'NextToken':
            'string',
            'ReservedElasticsearchInstances': [
                {
                    'ReservationName':
                    'string',
                    'ReservedElasticsearchInstanceId':
                    'string',
                    'ReservedElasticsearchInstanceOfferingId':
                    'string',
                    'ElasticsearchInstanceType':
                    't2.medium.elasticsearch',
                    'StartTime':
                    datetime.datetime(2015, 1, 1),
                    'Duration':
                    123,
                    'FixedPrice':
                    123.0,
                    'UsagePrice':
                    123.0,
                    'CurrencyCode':
                    'string',
                    'ElasticsearchInstanceCount':
                    123,
                    'State':
                    'string',
                    'PaymentOption':
                    'ALL_UPFRONT',
                    'RecurringCharges': [
                        {
                            'RecurringChargeAmount': 123.0,
                            'RecurringChargeFrequency': 'string'
                        },
                    ]
                },
            ]
        }
        with patch.object(self.paginator, 'paginate', return_value=[ret_val]):
            self.assertEqual(
                boto3_elasticsearch.describe_reserved_elasticsearch_instances(
                    reserved_elasticsearch_instance_id='foo',
                    **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['ReservedElasticsearchInstances']
                    })

    def test_describe_reserved_elasticsearch_instances_error(self):
        '''
        Test that when calling describe_reserved_elasticsearch_instances and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.paginator,
                          'paginate',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'describe_reserved_elasticsearch_instances')):
            result = boto3_elasticsearch.describe_reserved_elasticsearch_instances(
                reserved_elasticsearch_instance_id='foo', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(
                    101, 'describe_reserved_elasticsearch_instances'))

    def test_get_compatible_elasticsearch_versions_positive(self):
        '''
        Test that when calling get_compatible_elasticsearch_versions and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'CompatibleElasticsearchVersions': [{
                'SourceVersion': 'string',
                'TargetVersions': [
                    'string',
                ]
            }]
        }
        with patch.object(self.conn,
                          'get_compatible_elasticsearch_versions',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.get_compatible_elasticsearch_versions(
                    domain_name='testdomain', **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['CompatibleElasticsearchVersions']
                    })

    def test_get_compatible_elasticsearch_versions_error(self):
        '''
        Test that when calling get_compatible_elasticsearch_versions and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'get_compatible_elasticsearch_versions',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'get_compatible_elasticsearch_versions')):
            result = boto3_elasticsearch.get_compatible_elasticsearch_versions(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101,
                                     'get_compatible_elasticsearch_versions'))

    def test_get_upgrade_history_positive(self):
        '''
        Test that when calling get_upgrade_history and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'UpgradeHistories': [{
                'UpgradeName':
                'string',
                'StartTimestamp':
                datetime.datetime(2015, 1, 1),
                'UpgradeStatus':
                'IN_PROGRESS',
                'StepsList': [{
                    'UpgradeStep': 'PRE_UPGRADE_CHECK',
                    'UpgradeStepStatus': 'IN_PROGRESS',
                    'Issues': [
                        'string',
                    ],
                    'ProgressPercent': 123.0
                }]
            }],
            'NextToken':
            'string'
        }
        with patch.object(self.paginator, 'paginate', return_value=[ret_val]):
            self.assertEqual(
                boto3_elasticsearch.get_upgrade_history(
                    domain_name='testdomain', **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['UpgradeHistories']
                    })

    def test_get_upgrade_history_error(self):
        '''
        Test that when calling get_upgrade_history and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.paginator,
                          'paginate',
                          side_effect=ClientError(ERROR_CONTENT,
                                                  'get_upgrade_history')):
            result = boto3_elasticsearch.get_upgrade_history(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'get_upgrade_history'))

    def test_get_upgrade_status_positive(self):
        '''
        Test that when calling get_upgrade_status and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'UpgradeStep': 'PRE_UPGRADE_CHECK',
            'StepStatus': 'IN_PROGRESS',
            'UpgradeName': 'string',
            'ResponseMetadata': None,
        }
        with patch.object(self.conn,
                          'get_upgrade_status',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.get_upgrade_status(
                    domain_name='testdomain', **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val
                    })

    def test_get_upgrade_status_error(self):
        '''
        Test that when calling get_upgrade_status and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'get_upgrade_status',
                          side_effect=ClientError(ERROR_CONTENT,
                                                  'get_upgrade_status')):
            result = boto3_elasticsearch.get_upgrade_status(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'get_upgrade_status'))

    def test_list_domain_names_positive(self):
        '''
        Test that when calling list_domain_names and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {'DomainNames': [{'DomainName': 'string'}]}
        with patch.object(self.conn, 'list_domain_names',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.list_domain_names(**CONN_PARAMETERS), {
                    'result':
                    True,
                    'response':
                    [item['DomainName'] for item in ret_val['DomainNames']]
                })

    def test_list_domain_names_error(self):
        '''
        Test that when calling list_domain_names and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'list_domain_names',
                          side_effect=ClientError(ERROR_CONTENT,
                                                  'list_domain_names')):
            result = boto3_elasticsearch.list_domain_names(**CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(result.get('error', ''),
                             ERROR_MESSAGE.format(101, 'list_domain_names'))

    def test_list_elasticsearch_instance_types_positive(self):
        '''
        Test that when calling list_elasticsearch_instance_types and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'ElasticsearchInstanceTypes': [
                'm3.medium.elasticsearch',
                'm3.large.elasticsearch',
                'm3.xlarge.elasticsearch',
                'm3.2xlarge.elasticsearch',
                'm4.large.elasticsearch',
                'm4.xlarge.elasticsearch',
                'm4.2xlarge.elasticsearch',
                'm4.4xlarge.elasticsearch',
                'm4.10xlarge.elasticsearch',
                't2.micro.elasticsearch',
                't2.small.elasticsearch',
                't2.medium.elasticsearch',
                'r3.large.elasticsearch',
                'r3.xlarge.elasticsearch',
                'r3.2xlarge.elasticsearch',
                'r3.4xlarge.elasticsearch',
                'r3.8xlarge.elasticsearch',
                'i2.xlarge.elasticsearch',
                'i2.2xlarge.elasticsearch',
                'd2.xlarge.elasticsearch',
                'd2.2xlarge.elasticsearch',
                'd2.4xlarge.elasticsearch',
                'd2.8xlarge.elasticsearch',
                'c4.large.elasticsearch',
                'c4.xlarge.elasticsearch',
                'c4.2xlarge.elasticsearch',
                'c4.4xlarge.elasticsearch',
                'c4.8xlarge.elasticsearch',
                'r4.large.elasticsearch',
                'r4.xlarge.elasticsearch',
                'r4.2xlarge.elasticsearch',
                'r4.4xlarge.elasticsearch',
                'r4.8xlarge.elasticsearch',
                'r4.16xlarge.elasticsearch',
                'i3.large.elasticsearch',
                'i3.xlarge.elasticsearch',
                'i3.2xlarge.elasticsearch',
                'i3.4xlarge.elasticsearch',
                'i3.8xlarge.elasticsearch',
                'i3.16xlarge.elasticsearch',
            ],
            'NextToken':
            'string'
        }
        with patch.object(self.paginator, 'paginate', return_value=[ret_val]):
            self.assertEqual(
                boto3_elasticsearch.list_elasticsearch_instance_types(
                    elasticsearch_version='1.0', **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['ElasticsearchInstanceTypes']
                    })

    def test_list_elasticsearch_instance_types_error(self):
        '''
        Test that when calling list_elasticsearch_instance_types and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.paginator,
                          'paginate',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'list_elasticsearch_instance_types')):
            result = boto3_elasticsearch.list_elasticsearch_instance_types(
                elasticsearch_version='1.0', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101, 'list_elasticsearch_instance_types'))

    def test_list_elasticsearch_versions_positive(self):
        '''
        Test that when calling list_elasticsearch_versions and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {'ElasticsearchVersions': ['string'], 'NextToken': 'string'}
        with patch.object(self.paginator, 'paginate', return_value=[ret_val]):
            self.assertEqual(
                boto3_elasticsearch.list_elasticsearch_versions(
                    **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['ElasticsearchVersions']
                    })

    def test_list_elasticsearch_versions_error(self):
        '''
        Test that when calling list_elasticsearch_versions and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.paginator,
                          'paginate',
                          side_effect=ClientError(
                              ERROR_CONTENT, 'list_elasticsearch_versions')):
            result = boto3_elasticsearch.list_elasticsearch_versions(
                **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101, 'list_elasticsearch_versions'))

    def test_purchase_reserved_elasticsearch_instance_offering_positive(self):
        '''
        Test that when calling purchase_reserved_elasticsearch_instance_offering and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'ReservedElasticsearchInstanceId': 'string',
            'ReservationName': 'string'
        }
        with patch.object(self.conn,
                          'purchase_reserved_elasticsearch_instance_offering',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.
                purchase_reserved_elasticsearch_instance_offering(
                    reserved_elasticsearch_instance_offering_id='foo',
                    reservation_name='bar',
                    **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val
                    })

    def test_purchase_reserved_elasticsearch_instance_offering_error(self):
        '''
        Test that when calling purchase_reserved_elasticsearch_instance_offering and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(
                self.conn,
                'purchase_reserved_elasticsearch_instance_offering',
                side_effect=ClientError(
                    ERROR_CONTENT,
                    'purchase_reserved_elasticsearch_instance_offering')):
            result = boto3_elasticsearch.purchase_reserved_elasticsearch_instance_offering(
                reserved_elasticsearch_instance_offering_id='foo',
                reservation_name='bar',
                **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(
                    101, 'purchase_reserved_elasticsearch_instance_offering'))

    def test_start_elasticsearch_service_software_update_positive(self):
        '''
        Test that when calling start_elasticsearch_service_software_update and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'ServiceSoftwareOptions': {
                'CurrentVersion': 'string',
                'NewVersion': 'string',
                'UpdateAvailable': True,
                'Cancellable': True,
                'UpdateStatus': 'PENDING_UPDATE',
                'Description': 'string',
                'AutomatedUpdateDate': datetime.datetime(2015, 1, 1)
            }
        }
        with patch.object(self.conn,
                          'start_elasticsearch_service_software_update',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.
                start_elasticsearch_service_software_update(
                    domain_name='testdomain', **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val['ServiceSoftwareOptions']
                    })

    def test_start_elasticsearch_service_software_update_error(self):
        '''
        Test that when calling start_elasticsearch_service_software_update and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'start_elasticsearch_service_software_update',
                          side_effect=ClientError(
                              ERROR_CONTENT,
                              'start_elasticsearch_service_software_update')):
            result = boto3_elasticsearch.start_elasticsearch_service_software_update(
                domain_name='testdomain', **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(
                    101, 'start_elasticsearch_service_software_update'))

    def test_upgrade_elasticsearch_domain_positive(self):
        '''
        Test that when calling upgrade_elasticsearch_domain and it
        succeeds, it returns {'result': True, 'response': some_value}.
        '''
        ret_val = {
            'DomainName': 'string',
            'TargetVersion': 'string',
            'PerformCheckOnly': True
        }
        with patch.object(self.conn,
                          'upgrade_elasticsearch_domain',
                          return_value=ret_val):
            self.assertEqual(
                boto3_elasticsearch.upgrade_elasticsearch_domain(
                    domain_name='testdomain',
                    target_version='1.1',
                    **CONN_PARAMETERS), {
                        'result': True,
                        'response': ret_val
                    })

    def test_upgrade_elasticsearch_domain_error(self):
        '''
        Test that when calling upgrade_elasticsearch_domain and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        '''
        with patch.object(self.conn,
                          'upgrade_elasticsearch_domain',
                          side_effect=ClientError(
                              ERROR_CONTENT, 'upgrade_elasticsearch_domain')):
            result = boto3_elasticsearch.upgrade_elasticsearch_domain(
                domain_name='testdomain',
                target_version='1.1',
                **CONN_PARAMETERS)
            self.assertFalse(result['result'])
            self.assertEqual(
                result.get('error', ''),
                ERROR_MESSAGE.format(101, 'upgrade_elasticsearch_domain'))
Ejemplo n.º 4
0
class Boto3modTestCase(TestCase, LoaderModuleMockMixin):
    """
    TestCase for salt.utils.boto3mod module
    """

    region = "us-east-1"
    service = "test-service"
    resource_name = "test-resource"
    resource_id = "test-resource-id"
    access_key = "GKTADJGHEIQSXMKKRBJ08H"
    secret_key = "askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs"
    conn_parameters = {}
    error_message = (
        "An error occurred ({}) when calling the {} operation: Test-defined error"
    )
    error_content = {"Error": {"Code": 101, "Message": "Test-defined error"}}
    session_ret = {}
    conn = None

    def setup_loader_modules(self):
        self.opts = {
            "__salt__": {
                "config.option": salt.config.DEFAULT_MINION_OPTS.copy()
            }
        }
        return {boto3mod: self.opts}

    def setUp(self):
        super().setUp()
        del self.opts

        # Set up MagicMock to replace the boto3 session
        # connections keep getting cached from prior tests, can't find the
        # correct context object to clear it. So randomize the cache key, to prevent any
        # cache hits
        self.conn_parameters = {
            "region": self.region,
            "keyid": self.secret_key,
            "profile": {},
        }
        self.conn_parameters["key"] = "".join(
            random.choice(string.ascii_lowercase + string.digits)
            for _ in range(50))

        self.not_found_error = ClientError(
            {
                "Error": {
                    "Code": "ResourceNotFoundException",
                    "Message": "Test-defined error",
                }
            },
            "msg",
        )

        self.conn = MagicMock()
        self.addCleanup(delattr, self, "conn")
        self.patcher = patch("boto3.session.Session")
        self.addCleanup(self.patcher.stop)
        self.addCleanup(delattr, self, "patcher")
        mock_session = self.patcher.start()
        session_instance = mock_session.return_value
        session_instance.configure_mock(client=MagicMock(
            return_value=self.conn))
        self.paginator = MagicMock()
        self.addCleanup(delattr, self, "paginator")
        self.conn.configure_mock(get_paginator=MagicMock(
            return_value=self.paginator))

    def test_set_and_get_with_no_auth_params(self):
        boto3mod.cache_id(self.service,
                          self.resource_name,
                          resource_id=self.resource_id)
        self.assertEqual(boto3mod.cache_id(self.service, self.resource_name),
                         self.resource_id)

    def test_set_and_get_with_explicit_auth_params(self):
        boto3mod.cache_id(self.service,
                          self.resource_name,
                          resource_id=self.resource_id,
                          **self.conn_parameters)
        self.assertEqual(
            boto3mod.cache_id(self.service, self.resource_name,
                              **self.conn_parameters),
            self.resource_id,
        )

    def test_set_and_get_with_different_region_returns_none(self):
        boto3mod.cache_id(
            self.service,
            self.resource_name,
            resource_id=self.resource_id,
            region="us-east-1",
        )
        self.assertEqual(
            boto3mod.cache_id(self.service,
                              self.resource_name,
                              region="us-west-2"),
            None,
        )

    def test_set_and_get_after_invalidation_returns_none(self):
        boto3mod.cache_id(self.service,
                          self.resource_name,
                          resource_id=self.resource_id)
        boto3mod.cache_id(
            self.service,
            self.resource_name,
            resource_id=self.resource_id,
            invalidate=True,
        )
        self.assertEqual(boto3mod.cache_id(self.service, self.resource_name),
                         None)

    def test_partial(self):
        cache_id = boto3mod.cache_id_func(self.service)
        cache_id(self.resource_name, resource_id=self.resource_id)
        self.assertEqual(cache_id(self.resource_name), self.resource_id)
Ejemplo n.º 5
0
class Boto3Route53TestCase(TestCase, LoaderModuleMockMixin):
    """
    TestCase for salt.modules.boto3_route53 moodule
    """

    conn = None

    def setup_loader_modules(self):
        self.opts = salt.config.DEFAULT_MINION_OPTS.copy()
        utils = salt.loader.utils(
            self.opts,
            whitelist=["boto3", "args", "systemd", "path", "platform"],
            context={},
        )
        return {boto3_route53: {"__utils__": utils}}

    def setUp(self):
        super().setUp()
        boto3_route53.__init__(self.opts)
        del self.opts

        # Set up MagicMock to replace the boto3 session
        # connections keep getting cached from prior tests, can't find the
        # correct context object to clear it. So randomize the cache key, to prevent any
        # cache hits
        CONN_PARAMETERS["key"] = "".join(
            random.choice(string.ascii_lowercase + string.digits)
            for _ in range(50))

        self.conn = MagicMock()
        self.addCleanup(delattr, self, "conn")
        self.patcher = patch("boto3.session.Session")
        self.addCleanup(self.patcher.stop)
        self.addCleanup(delattr, self, "patcher")
        mock_session = self.patcher.start()
        session_instance = mock_session.return_value
        session_instance.configure_mock(client=MagicMock(
            return_value=self.conn))
        self.paginator = MagicMock()
        self.addCleanup(delattr, self, "paginator")
        self.conn.configure_mock(get_paginator=MagicMock(
            return_value=self.paginator))

    def test_get_resource_records(self):
        """
        Test get_resource_records behaviour.
        """

        # The patch below is not neccesary per se,
        # as .exists returns positive as long as no exception is raised.
        with patch.object(
                self.conn,
                "list_resource_record_sets",
                return_value=LIST_RESOURCE_RECORD_SETS_RETURN,
        ):
            self.assertEqual(
                boto3_route53.get_resource_records(
                    HostedZoneId="Z2P70J7EXAMPLE",
                    StartRecordName="blog.saltstack.furniture.",
                    StartRecordType="A",
                    **CONN_PARAMETERS),
                [{
                    "Name": "blog.saltstack.furniture.",
                    "ResourceRecords": [{
                        "Value": "127.0.0.1"
                    }],
                    "TTL": 60,
                    "Type": "A",
                }],
            )
class Boto3ElasticsearchTestCase(TestCase, LoaderModuleMockMixin):
    """
    TestCase for salt.modules.boto3_elasticsearch module
    """

    conn = None

    def setup_loader_modules(self):
        self.opts = salt.config.DEFAULT_MINION_OPTS.copy()
        utils = salt.loader.utils(
            self.opts,
            whitelist=["boto3", "args", "systemd", "path", "platform"],
            context={},
        )
        return {boto3_elasticsearch: {"__utils__": utils}}

    def setUp(self):
        super().setUp()
        boto3_elasticsearch.__init__(self.opts)
        del self.opts

        # Set up MagicMock to replace the boto3 session
        # connections keep getting cached from prior tests, can't find the
        # correct context object to clear it. So randomize the cache key, to prevent any
        # cache hits
        CONN_PARAMETERS["key"] = "".join(
            random.choice(string.ascii_lowercase + string.digits) for _ in range(50)
        )

        self.conn = MagicMock()
        self.addCleanup(delattr, self, "conn")
        self.patcher = patch("boto3.session.Session")
        self.addCleanup(self.patcher.stop)
        self.addCleanup(delattr, self, "patcher")
        mock_session = self.patcher.start()
        session_instance = mock_session.return_value
        session_instance.configure_mock(client=MagicMock(return_value=self.conn))
        self.paginator = MagicMock()
        self.addCleanup(delattr, self, "paginator")
        self.conn.configure_mock(get_paginator=MagicMock(return_value=self.paginator))

    def test_describe_elasticsearch_domain_positive(self):
        """
        Test that when describing a domain when the domain actually exists,
        the .exists method returns a dict with 'result': True
        and 'response' with the domain status information.
        """
        # The patch below is not neccesary per se,
        # as .exists returns positive as long as no exception is raised.
        with patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            assert boto3_elasticsearch.describe_elasticsearch_domain(
                domain_name="testdomain", **CONN_PARAMETERS
            ) == {"result": True, "response": DOMAIN_RET}

    def test_describe_elasticsearch_domain_error(self):
        """
        Test that when describing a domain when the domain does not exist,
        the .exists method returns a dict with 'result': False
        and 'error' with boto's ResourceNotFoundException.
        """
        with patch.object(self.conn, "describe_elasticsearch_domain", side_effect=NOT_FOUND_ERROR):
            result = boto3_elasticsearch.describe_elasticsearch_domain(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert result.get("error", "") == ERROR_MESSAGE.format(
                "ResourceNotFoundException", "msg"
            )
            assert not result["result"]

    def test_create_elasticsearch_domain_positive(self):
        """
        Test that when creating a domain, and it succeeds,
        the .create method returns a dict with 'result': True
        and 'response' with the newly created domain's status information.
        """
        with patch.object(
            self.conn,
            "create_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            kwargs = {
                "elasticsearch_version": DOMAIN_RET["ElasticsearchVersion"],
                "elasticsearch_cluster_config": DOMAIN_RET["ElasticsearchClusterConfig"],
                "ebs_options": DOMAIN_RET["EBSOptions"],
                "access_policies": DOMAIN_RET["AccessPolicies"],
                "snapshot_options": DOMAIN_RET["SnapshotOptions"],
                "vpc_options": DOMAIN_RET["VPCOptions"],
                "cognito_options": DOMAIN_RET["CognitoOptions"],
                "encryption_at_rest_options": DOMAIN_RET["EncryptionAtRestOptions"],
                "advanced_options": DOMAIN_RET["AdvancedOptions"],
            }
            kwargs.update(CONN_PARAMETERS)
            assert boto3_elasticsearch.create_elasticsearch_domain(
                domain_name="testdomain", **kwargs
            ) == {"result": True, "response": DOMAIN_RET}

    def test_create_elasticsearch_domain_error(self):
        """
        Test that when creating a domain, and boto3 returns an error,
        the .create method returns a dict with 'result': False
        and 'error' with the error reported by boto3.
        """
        with patch.object(
            self.conn,
            "create_elasticsearch_domain",
            side_effect=ClientError(ERROR_CONTENT, "create_domain"),
        ):
            kwargs = {
                "elasticsearch_version": DOMAIN_RET["ElasticsearchVersion"],
                "elasticsearch_cluster_config": DOMAIN_RET["ElasticsearchClusterConfig"],
                "ebs_options": DOMAIN_RET["EBSOptions"],
                "access_policies": DOMAIN_RET["AccessPolicies"],
                "snapshot_options": DOMAIN_RET["SnapshotOptions"],
                "vpc_options": DOMAIN_RET["VPCOptions"],
                "cognito_options": DOMAIN_RET["CognitoOptions"],
                "encryption_at_rest_options": DOMAIN_RET["EncryptionAtRestOptions"],
                "advanced_options": DOMAIN_RET["AdvancedOptions"],
            }
            kwargs.update(CONN_PARAMETERS)
            result = boto3_elasticsearch.create_elasticsearch_domain("testdomain", **kwargs)
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "create_domain")

    def test_delete_domain_positive(self):
        """
        Test that when deleting a domain, and it succeeds,
        the .delete method returns {'result': True}.
        """
        with patch.object(self.conn, "delete_elasticsearch_domain"):
            assert boto3_elasticsearch.delete_elasticsearch_domain(
                "testdomain", **CONN_PARAMETERS
            ) == {"result": True}

    def test_delete_domain_error(self):
        """
        Test that when deleting a domain, and boto3 returns an error,
        the .delete method returns {'result': False, 'error' :'the error'}.
        """
        with patch.object(
            self.conn,
            "delete_elasticsearch_domain",
            side_effect=ClientError(ERROR_CONTENT, "delete_domain"),
        ):
            result = boto3_elasticsearch.delete_elasticsearch_domain(
                "testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "delete_domain")

    def test_update_domain_positive(self):
        """
        Test that when updating a domain succeeds, the .update method returns {'result': True}.
        """
        with patch.object(
            self.conn,
            "update_elasticsearch_domain_config",
            return_value={"DomainConfig": DOMAIN_RET},
        ):
            kwargs = {
                "elasticsearch_cluster_config": DOMAIN_RET["ElasticsearchClusterConfig"],
                "ebs_options": DOMAIN_RET["EBSOptions"],
                "snapshot_options": DOMAIN_RET["SnapshotOptions"],
                "vpc_options": DOMAIN_RET["VPCOptions"],
                "cognito_options": DOMAIN_RET["CognitoOptions"],
                "advanced_options": DOMAIN_RET["AdvancedOptions"],
                "access_policies": DOMAIN_RET["AccessPolicies"],
                "log_publishing_options": {},
            }

            kwargs.update(CONN_PARAMETERS)
            assert boto3_elasticsearch.update_elasticsearch_domain_config(
                "testdomain", **kwargs
            ) == {"result": True, "response": DOMAIN_RET}

    def test_update_domain_error(self):
        """
        Test that when updating a domain fails, and boto3 returns an error,
        the .update method returns the error.
        """
        with patch.object(
            self.conn,
            "update_elasticsearch_domain_config",
            side_effect=ClientError(ERROR_CONTENT, "update_domain"),
        ):
            kwargs = {
                "elasticsearch_cluster_config": DOMAIN_RET["ElasticsearchClusterConfig"],
                "ebs_options": DOMAIN_RET["EBSOptions"],
                "snapshot_options": DOMAIN_RET["SnapshotOptions"],
                "vpc_options": DOMAIN_RET["VPCOptions"],
                "cognito_options": DOMAIN_RET["CognitoOptions"],
                "advanced_options": DOMAIN_RET["AdvancedOptions"],
                "access_policies": DOMAIN_RET["AccessPolicies"],
                "log_publishing_options": {},
            }
            kwargs.update(CONN_PARAMETERS)
            result = boto3_elasticsearch.update_elasticsearch_domain_config("testdomain", **kwargs)
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "update_domain")

    def test_add_tags_positive(self):
        """
        Test that when adding tags is successful, the .add_tags method returns {'result': True}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            assert boto3_elasticsearch.add_tags(
                "testdomain", tags={"foo": "bar", "baz": "qux"}, **CONN_PARAMETERS
            ) == {"result": True}

    def test_add_tags_error(self):
        """
        Test that when adding tags fails, and boto3 returns an error,
        the .add_tags function returns {'tagged': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn, "add_tags", side_effect=ClientError(ERROR_CONTENT, "add_tags")
        ), patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            result = boto3_elasticsearch.add_tags(
                "testdomain", tags={"foo": "bar", "baz": "qux"}, **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "add_tags")

    def test_remove_tags_positive(self):
        """
        Test that when removing tags is successful, the .remove_tags method returns {'tagged': True}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            assert boto3_elasticsearch.remove_tags(
                tag_keys=["foo", "bar"], domain_name="testdomain", **CONN_PARAMETERS
            ) == {"result": True}

    def test_remove_tag_error(self):
        """
        Test that when removing tags fails, and boto3 returns an error,
        the .remove_tags method returns {'tagged': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "remove_tags",
            side_effect=ClientError(ERROR_CONTENT, "remove_tags"),
        ), patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            result = boto3_elasticsearch.remove_tags(
                tag_keys=["foo", "bar"], domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "remove_tags")

    def test_list_tags_positive(self):
        """
        Test that when listing tags is successful,
        the .list_tags method returns a dict with key 'tags'.
        Also test that the tags returned are manipulated properly (i.e. transformed
        into a dict with tags).
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ), patch.object(
            self.conn,
            "list_tags",
            return_value={"TagList": [{"Key": "foo", "Value": "bar"}]},
        ):
            result = boto3_elasticsearch.list_tags(domain_name="testdomain", **CONN_PARAMETERS)
            assert result == {"result": True, "response": {"foo": "bar"}}

    def test_list_tags_error(self):
        """
        Test that when listing tags causes boto3 to return an error,
        the .list_tags method returns the error.
        """
        with patch.object(
            self.conn, "list_tags", side_effect=ClientError(ERROR_CONTENT, "list_tags")
        ), patch.object(
            self.conn,
            "describe_elasticsearch_domain",
            return_value={"DomainStatus": DOMAIN_RET},
        ):
            result = boto3_elasticsearch.list_tags(domain_name="testdomain", **CONN_PARAMETERS)
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "list_tags")

    def test_cancel_elasticsearch_service_software_update_positive(self):
        """
        Test that when calling cancel_elasticsearch_service_software_update and
        it is successful, it returns {'result': True}.
        """
        retval = {
            "ServiceSoftwareOptions": {
                "CurrentVersion": "string",
                "NewVersion": "string",
                "UpdateAvailable": True,
                "Cancellable": True,
                "UpdateStatus": "ELIGIBLE",
                "Description": "string",
                "AutomatedUpdateDate": datetime.datetime(2015, 1, 1),
            }
        }
        with patch.object(
            self.conn,
            "cancel_elasticsearch_service_software_update",
            return_value=retval,
        ):
            result = boto3_elasticsearch.cancel_elasticsearch_service_software_update(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert result == {"result": True}

    def test_cancel_elasticsearch_service_software_update_error(self):
        """
        Test that when calling cancel_elasticsearch_service_software_update and
        boto3 returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "cancel_elasticsearch_service_software_update",
            side_effect=ClientError(ERROR_CONTENT, "cancel_elasticsearch_service_software_update"),
        ):
            result = boto3_elasticsearch.cancel_elasticsearch_service_software_update(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "cancel_elasticsearch_service_software_update"
            )

    def test_delete_elasticsearch_service_role_positive(self):
        """
        Test that when calling delete_elasticsearch_service_role and
        it is successful, it returns {'result': True}.
        """
        with patch.object(self.conn, "delete_elasticsearch_service_role", return_value=None):
            result = boto3_elasticsearch.delete_elasticsearch_service_role(**CONN_PARAMETERS)
            assert result == {"result": True}

    def test_delete_elasticsearch_service_role_error(self):
        """
        Test that when calling delete_elasticsearch_service_role and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "delete_elasticsearch_service_role",
            side_effect=ClientError(ERROR_CONTENT, "delete_elasticsearch_service_role"),
        ):
            result = boto3_elasticsearch.delete_elasticsearch_service_role(**CONN_PARAMETERS)
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "delete_elasticsearch_service_role"
            )

    def test_describe_elasticsearch_domain_config_positive(self):
        """
        Test that when calling describe_elasticsearch_domain_config and
        it is successful, it returns {'result': True}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domain_config",
            return_value={"DomainConfig": DOMAIN_RET},
        ):
            assert boto3_elasticsearch.describe_elasticsearch_domain_config(
                "testdomain", **CONN_PARAMETERS
            ) == {"result": True, "response": DOMAIN_RET}

    def test_describe_elasticsearch_domain_config_error(self):
        """
        Test that when calling describe_elasticsearch_domain_config and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domain_config",
            side_effect=ClientError(ERROR_CONTENT, "describe_elasticsearch_domain_config"),
        ):
            result = boto3_elasticsearch.describe_elasticsearch_domain_config(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "describe_elasticsearch_domain_config"
            )

    def test_describe_elasticsearch_domains_positive(self):
        """
        Test that when calling describe_elasticsearch_domains and it is successful,
        it returns {'result': True, 'response': some_data}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domains",
            return_value={"DomainStatusList": [DOMAIN_RET]},
        ):
            assert boto3_elasticsearch.describe_elasticsearch_domains(
                domain_names=["test_domain"], **CONN_PARAMETERS
            ) == {"result": True, "response": [DOMAIN_RET]}

    def test_describe_elasticsearch_domains_error(self):
        """
        Test that when calling describe_elasticsearch_domains and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_domains",
            side_effect=ClientError(ERROR_CONTENT, "describe_elasticsearch_domains"),
        ):
            result = boto3_elasticsearch.describe_elasticsearch_domains(
                domain_names=["testdomain"], **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "describe_elasticsearch_domains"
            )

    def test_describe_elasticsearch_instance_type_limits_positive(self):
        """
        Test that when calling describe_elasticsearch_instance_type_limits and
        it succeeds, it returns {'result': True, 'response' some_value}.
        """
        ret_val = {
            "LimitsByRole": {
                "string": {
                    "StorageTypes": [
                        {
                            "StorageTypeName": "string",
                            "StorageSubTypeName": "string",
                            "StorageTypeLimits": [
                                {"LimitName": "string", "LimitValues": ["string"]}
                            ],
                        }
                    ],
                    "InstanceLimits": {
                        "InstanceCountLimits": {
                            "MinimumInstanceCount": 123,
                            "MaximumInstanceCount": 123,
                        }
                    },
                    "AdditionalLimits": [{"LimitName": "string", "LimitValues": ["string"]}],
                }
            }
        }
        with patch.object(
            self.conn,
            "describe_elasticsearch_instance_type_limits",
            return_value=ret_val,
        ):
            assert boto3_elasticsearch.describe_elasticsearch_instance_type_limits(
                domain_name="testdomain",
                instance_type="foo",
                elasticsearch_version="1.0",
                **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val["LimitsByRole"]}

    def test_describe_elasticsearch_instance_type_limits_error(self):
        """
        Test that when calling describe_elasticsearch_instance_type_limits and boto3 returns
        an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "describe_elasticsearch_instance_type_limits",
            side_effect=ClientError(ERROR_CONTENT, "describe_elasticsearch_instance_type_limits"),
        ):
            result = boto3_elasticsearch.describe_elasticsearch_instance_type_limits(
                domain_name="testdomain",
                instance_type="foo",
                elasticsearch_version="1.0",
                **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "describe_elasticsearch_instance_type_limits"
            )

    def test_describe_reserved_elasticsearch_instance_offerings_positive(self):
        """
        Test that when calling describe_reserved_elasticsearch_instance_offerings
        and it succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "NextToken": "string",
            "ReservedElasticsearchInstanceOfferings": [
                {
                    "ReservedElasticsearchInstanceOfferingId": "string",
                    "ElasticsearchInstanceType": "t2.medium.elasticsearch",
                    "Duration": 123,
                    "FixedPrice": 123.0,
                    "UsagePrice": 123.0,
                    "CurrencyCode": "string",
                    "PaymentOption": "NO_UPFRONT",
                    "RecurringCharges": [
                        {
                            "RecurringChargeAmount": 123.0,
                            "RecurringChargeFrequency": "string",
                        }
                    ],
                }
            ],
        }
        with patch.object(self.paginator, "paginate", return_value=[ret_val]):
            assert boto3_elasticsearch.describe_reserved_elasticsearch_instance_offerings(
                reserved_elasticsearch_instance_offering_id="foo", **CONN_PARAMETERS
            ) == {
                "result": True,
                "response": ret_val["ReservedElasticsearchInstanceOfferings"],
            }

    def test_describe_reserved_elasticsearch_instance_offerings_error(self):
        """
        Test that when calling describe_reserved_elasticsearch_instance_offerings
        and boto3 returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.paginator,
            "paginate",
            side_effect=ClientError(
                ERROR_CONTENT, "describe_reserved_elasticsearch_instance_offerings"
            ),
        ):
            result = boto3_elasticsearch.describe_reserved_elasticsearch_instance_offerings(
                reserved_elasticsearch_instance_offering_id="foo", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "describe_reserved_elasticsearch_instance_offerings"
            )

    def test_describe_reserved_elasticsearch_instances_positive(self):
        """
        Test that when calling describe_reserved_elasticsearch_instances and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "NextToken": "string",
            "ReservedElasticsearchInstances": [
                {
                    "ReservationName": "string",
                    "ReservedElasticsearchInstanceId": "string",
                    "ReservedElasticsearchInstanceOfferingId": "string",
                    "ElasticsearchInstanceType": "t2.medium.elasticsearch",
                    "StartTime": datetime.datetime(2015, 1, 1),
                    "Duration": 123,
                    "FixedPrice": 123.0,
                    "UsagePrice": 123.0,
                    "CurrencyCode": "string",
                    "ElasticsearchInstanceCount": 123,
                    "State": "string",
                    "PaymentOption": "ALL_UPFRONT",
                    "RecurringCharges": [
                        {
                            "RecurringChargeAmount": 123.0,
                            "RecurringChargeFrequency": "string",
                        },
                    ],
                },
            ],
        }
        with patch.object(self.paginator, "paginate", return_value=[ret_val]):
            assert boto3_elasticsearch.describe_reserved_elasticsearch_instances(
                reserved_elasticsearch_instance_id="foo", **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val["ReservedElasticsearchInstances"]}

    def test_describe_reserved_elasticsearch_instances_error(self):
        """
        Test that when calling describe_reserved_elasticsearch_instances and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.paginator,
            "paginate",
            side_effect=ClientError(ERROR_CONTENT, "describe_reserved_elasticsearch_instances"),
        ):
            result = boto3_elasticsearch.describe_reserved_elasticsearch_instances(
                reserved_elasticsearch_instance_id="foo", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "describe_reserved_elasticsearch_instances"
            )

    def test_get_compatible_elasticsearch_versions_positive(self):
        """
        Test that when calling get_compatible_elasticsearch_versions and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "CompatibleElasticsearchVersions": [
                {"SourceVersion": "string", "TargetVersions": ["string"]}
            ]
        }
        with patch.object(self.conn, "get_compatible_elasticsearch_versions", return_value=ret_val):
            assert boto3_elasticsearch.get_compatible_elasticsearch_versions(
                domain_name="testdomain", **CONN_PARAMETERS
            ) == {
                "result": True,
                "response": ret_val["CompatibleElasticsearchVersions"],
            }

    def test_get_compatible_elasticsearch_versions_error(self):
        """
        Test that when calling get_compatible_elasticsearch_versions and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "get_compatible_elasticsearch_versions",
            side_effect=ClientError(ERROR_CONTENT, "get_compatible_elasticsearch_versions"),
        ):
            result = boto3_elasticsearch.get_compatible_elasticsearch_versions(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "get_compatible_elasticsearch_versions"
            )

    def test_get_upgrade_history_positive(self):
        """
        Test that when calling get_upgrade_history and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "UpgradeHistories": [
                {
                    "UpgradeName": "string",
                    "StartTimestamp": datetime.datetime(2015, 1, 1),
                    "UpgradeStatus": "IN_PROGRESS",
                    "StepsList": [
                        {
                            "UpgradeStep": "PRE_UPGRADE_CHECK",
                            "UpgradeStepStatus": "IN_PROGRESS",
                            "Issues": ["string"],
                            "ProgressPercent": 123.0,
                        }
                    ],
                }
            ],
            "NextToken": "string",
        }
        with patch.object(self.paginator, "paginate", return_value=[ret_val]):
            assert boto3_elasticsearch.get_upgrade_history(
                domain_name="testdomain", **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val["UpgradeHistories"]}

    def test_get_upgrade_history_error(self):
        """
        Test that when calling get_upgrade_history and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.paginator,
            "paginate",
            side_effect=ClientError(ERROR_CONTENT, "get_upgrade_history"),
        ):
            result = boto3_elasticsearch.get_upgrade_history(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "get_upgrade_history")

    def test_get_upgrade_status_positive(self):
        """
        Test that when calling get_upgrade_status and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "UpgradeStep": "PRE_UPGRADE_CHECK",
            "StepStatus": "IN_PROGRESS",
            "UpgradeName": "string",
            "ResponseMetadata": None,
        }
        with patch.object(self.conn, "get_upgrade_status", return_value=ret_val):
            assert boto3_elasticsearch.get_upgrade_status(
                domain_name="testdomain", **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val}

    def test_get_upgrade_status_error(self):
        """
        Test that when calling get_upgrade_status and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "get_upgrade_status",
            side_effect=ClientError(ERROR_CONTENT, "get_upgrade_status"),
        ):
            result = boto3_elasticsearch.get_upgrade_status(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "get_upgrade_status")

    def test_list_domain_names_positive(self):
        """
        Test that when calling list_domain_names and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {"DomainNames": [{"DomainName": "string"}]}
        with patch.object(self.conn, "list_domain_names", return_value=ret_val):
            assert boto3_elasticsearch.list_domain_names(**CONN_PARAMETERS) == {
                "result": True,
                "response": [item["DomainName"] for item in ret_val["DomainNames"]],
            }

    def test_list_domain_names_error(self):
        """
        Test that when calling list_domain_names and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "list_domain_names",
            side_effect=ClientError(ERROR_CONTENT, "list_domain_names"),
        ):
            result = boto3_elasticsearch.list_domain_names(**CONN_PARAMETERS)
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(101, "list_domain_names")

    def test_list_elasticsearch_instance_types_positive(self):
        """
        Test that when calling list_elasticsearch_instance_types and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "ElasticsearchInstanceTypes": [
                "m3.medium.elasticsearch",
                "m3.large.elasticsearch",
                "m3.xlarge.elasticsearch",
                "m3.2xlarge.elasticsearch",
                "m4.large.elasticsearch",
                "m4.xlarge.elasticsearch",
                "m4.2xlarge.elasticsearch",
                "m4.4xlarge.elasticsearch",
                "m4.10xlarge.elasticsearch",
                "t2.micro.elasticsearch",
                "t2.small.elasticsearch",
                "t2.medium.elasticsearch",
                "r3.large.elasticsearch",
                "r3.xlarge.elasticsearch",
                "r3.2xlarge.elasticsearch",
                "r3.4xlarge.elasticsearch",
                "r3.8xlarge.elasticsearch",
                "i2.xlarge.elasticsearch",
                "i2.2xlarge.elasticsearch",
                "d2.xlarge.elasticsearch",
                "d2.2xlarge.elasticsearch",
                "d2.4xlarge.elasticsearch",
                "d2.8xlarge.elasticsearch",
                "c4.large.elasticsearch",
                "c4.xlarge.elasticsearch",
                "c4.2xlarge.elasticsearch",
                "c4.4xlarge.elasticsearch",
                "c4.8xlarge.elasticsearch",
                "r4.large.elasticsearch",
                "r4.xlarge.elasticsearch",
                "r4.2xlarge.elasticsearch",
                "r4.4xlarge.elasticsearch",
                "r4.8xlarge.elasticsearch",
                "r4.16xlarge.elasticsearch",
                "i3.large.elasticsearch",
                "i3.xlarge.elasticsearch",
                "i3.2xlarge.elasticsearch",
                "i3.4xlarge.elasticsearch",
                "i3.8xlarge.elasticsearch",
                "i3.16xlarge.elasticsearch",
            ],
            "NextToken": "string",
        }
        with patch.object(self.paginator, "paginate", return_value=[ret_val]):
            assert boto3_elasticsearch.list_elasticsearch_instance_types(
                elasticsearch_version="1.0", **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val["ElasticsearchInstanceTypes"]}

    def test_list_elasticsearch_instance_types_error(self):
        """
        Test that when calling list_elasticsearch_instance_types and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.paginator,
            "paginate",
            side_effect=ClientError(ERROR_CONTENT, "list_elasticsearch_instance_types"),
        ):
            result = boto3_elasticsearch.list_elasticsearch_instance_types(
                elasticsearch_version="1.0", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "list_elasticsearch_instance_types"
            )

    def test_list_elasticsearch_versions_positive(self):
        """
        Test that when calling list_elasticsearch_versions and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {"ElasticsearchVersions": ["string"], "NextToken": "string"}
        with patch.object(self.paginator, "paginate", return_value=[ret_val]):
            assert boto3_elasticsearch.list_elasticsearch_versions(**CONN_PARAMETERS) == {
                "result": True,
                "response": ret_val["ElasticsearchVersions"],
            }

    def test_list_elasticsearch_versions_error(self):
        """
        Test that when calling list_elasticsearch_versions and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.paginator,
            "paginate",
            side_effect=ClientError(ERROR_CONTENT, "list_elasticsearch_versions"),
        ):
            result = boto3_elasticsearch.list_elasticsearch_versions(**CONN_PARAMETERS)
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "list_elasticsearch_versions"
            )

    def test_purchase_reserved_elasticsearch_instance_offering_positive(self):
        """
        Test that when calling purchase_reserved_elasticsearch_instance_offering and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "ReservedElasticsearchInstanceId": "string",
            "ReservationName": "string",
        }
        with patch.object(
            self.conn,
            "purchase_reserved_elasticsearch_instance_offering",
            return_value=ret_val,
        ):
            assert boto3_elasticsearch.purchase_reserved_elasticsearch_instance_offering(
                reserved_elasticsearch_instance_offering_id="foo",
                reservation_name="bar",
                **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val}

    def test_purchase_reserved_elasticsearch_instance_offering_error(self):
        """
        Test that when calling purchase_reserved_elasticsearch_instance_offering and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "purchase_reserved_elasticsearch_instance_offering",
            side_effect=ClientError(
                ERROR_CONTENT, "purchase_reserved_elasticsearch_instance_offering"
            ),
        ):
            result = boto3_elasticsearch.purchase_reserved_elasticsearch_instance_offering(
                reserved_elasticsearch_instance_offering_id="foo",
                reservation_name="bar",
                **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "purchase_reserved_elasticsearch_instance_offering"
            )

    def test_start_elasticsearch_service_software_update_positive(self):
        """
        Test that when calling start_elasticsearch_service_software_update and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "ServiceSoftwareOptions": {
                "CurrentVersion": "string",
                "NewVersion": "string",
                "UpdateAvailable": True,
                "Cancellable": True,
                "UpdateStatus": "PENDING_UPDATE",
                "Description": "string",
                "AutomatedUpdateDate": datetime.datetime(2015, 1, 1),
            }
        }
        with patch.object(
            self.conn,
            "start_elasticsearch_service_software_update",
            return_value=ret_val,
        ):
            assert boto3_elasticsearch.start_elasticsearch_service_software_update(
                domain_name="testdomain", **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val["ServiceSoftwareOptions"]}

    def test_start_elasticsearch_service_software_update_error(self):
        """
        Test that when calling start_elasticsearch_service_software_update and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "start_elasticsearch_service_software_update",
            side_effect=ClientError(ERROR_CONTENT, "start_elasticsearch_service_software_update"),
        ):
            result = boto3_elasticsearch.start_elasticsearch_service_software_update(
                domain_name="testdomain", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "start_elasticsearch_service_software_update"
            )

    def test_upgrade_elasticsearch_domain_positive(self):
        """
        Test that when calling upgrade_elasticsearch_domain and it
        succeeds, it returns {'result': True, 'response': some_value}.
        """
        ret_val = {
            "DomainName": "string",
            "TargetVersion": "string",
            "PerformCheckOnly": True,
        }
        with patch.object(self.conn, "upgrade_elasticsearch_domain", return_value=ret_val):
            assert boto3_elasticsearch.upgrade_elasticsearch_domain(
                domain_name="testdomain", target_version="1.1", **CONN_PARAMETERS
            ) == {"result": True, "response": ret_val}

    def test_upgrade_elasticsearch_domain_error(self):
        """
        Test that when calling upgrade_elasticsearch_domain and boto3
        returns an error, it returns {'result': False, 'error': 'the error'}.
        """
        with patch.object(
            self.conn,
            "upgrade_elasticsearch_domain",
            side_effect=ClientError(ERROR_CONTENT, "upgrade_elasticsearch_domain"),
        ):
            result = boto3_elasticsearch.upgrade_elasticsearch_domain(
                domain_name="testdomain", target_version="1.1", **CONN_PARAMETERS
            )
            assert not result["result"]
            assert result.get("error", "") == ERROR_MESSAGE.format(
                101, "upgrade_elasticsearch_domain"
            )
Ejemplo n.º 7
0
class SnapperTestCase(TestCase):
    def setUp(self):
        self.dbus_mock = MagicMock()
        self.DBusExceptionMock = MagicMock()  # pylint: disable=invalid-name
        self.dbus_mock.configure_mock(DBusException=self.DBusExceptionMock)
        snapper.dbus = self.dbus_mock
        snapper.snapper = MagicMock()

    def test__snapshot_to_data(self):
        data = snapper._snapshot_to_data(DBUS_RET['ListSnapshots'][0])  # pylint: disable=protected-access
        self.assertEqual(data['id'], 42)
        self.assertNotIn('pre', data)
        self.assertEqual(data['type'], 'pre')
        self.assertEqual(data['user'], 'root')
        self.assertEqual(data['timestamp'], 1457006571)
        self.assertEqual(data['description'], 'Some description')
        self.assertEqual(data['cleanup'], '')
        self.assertEqual(data['userdata']['userdata1'], 'userval1')

    @patch('salt.modules.snapper.snapper.ListSnapshots',
           MagicMock(return_value=DBUS_RET['ListSnapshots']))
    def test_list_snapshots(self):
        self.assertEqual(snapper.list_snapshots(), MODULE_RET["SNAPSHOTS"])

    @patch('salt.modules.snapper.snapper.GetSnapshot',
           MagicMock(return_value=DBUS_RET['ListSnapshots'][0]))
    def test_get_snapshot(self):
        self.assertEqual(snapper.get_snapshot(), MODULE_RET["SNAPSHOTS"][0])
        self.assertEqual(snapper.get_snapshot(number=42),
                         MODULE_RET["SNAPSHOTS"][0])
        self.assertNotEqual(snapper.get_snapshot(number=42),
                            MODULE_RET["SNAPSHOTS"][1])

    @patch('salt.modules.snapper.snapper.ListConfigs',
           MagicMock(return_value=DBUS_RET['ListConfigs']))
    def test_list_configs(self):
        self.assertEqual(snapper.list_configs(), MODULE_RET["LISTCONFIGS"])

    @patch('salt.modules.snapper.snapper.GetConfig',
           MagicMock(return_value=DBUS_RET['ListConfigs'][0]))
    def test_get_config(self):
        self.assertEqual(snapper.get_config(), DBUS_RET["ListConfigs"][0])

    @patch('salt.modules.snapper.snapper.SetConfig', MagicMock())
    def test_set_config(self):
        opts = {'sync_acl': True, 'dummy': False, 'foobar': 1234}
        self.assertEqual(snapper.set_config(opts), True)

    def test_status_to_string(self):
        self.assertEqual(snapper.status_to_string(1), ["created"])
        self.assertEqual(snapper.status_to_string(2), ["deleted"])
        self.assertEqual(snapper.status_to_string(4), ["type changed"])
        self.assertEqual(snapper.status_to_string(8), ["modified"])
        self.assertEqual(snapper.status_to_string(16), ["permission changed"])
        self.assertListEqual(snapper.status_to_string(24),
                             ["modified", "permission changed"])
        self.assertEqual(snapper.status_to_string(32), ["owner changed"])
        self.assertEqual(snapper.status_to_string(64), ["group changed"])
        self.assertListEqual(snapper.status_to_string(97),
                             ["created", "owner changed", "group changed"])
        self.assertEqual(snapper.status_to_string(128),
                         ["extended attributes changed"])
        self.assertEqual(snapper.status_to_string(256), ["ACL info changed"])

    @patch('salt.modules.snapper.snapper.CreateConfig', MagicMock())
    @patch('salt.modules.snapper.snapper.GetConfig',
           MagicMock(return_value=DBUS_RET['ListConfigs'][0]))
    def test_create_config(self):
        opts = {
            'name': 'testconfig',
            'subvolume': '/foo/bar/',
            'fstype': 'btrfs',
            'template': 'mytemplate',
            'extra_opts': {
                "NUMBER_CLEANUP": False
            },
        }
        with patch('salt.modules.snapper.set_config',
                   MagicMock()) as set_config_mock:
            self.assertEqual(snapper.create_config(**opts),
                             DBUS_RET['ListConfigs'][0])
            set_config_mock.assert_called_with("testconfig",
                                               **opts['extra_opts'])

        with patch('salt.modules.snapper.set_config',
                   MagicMock()) as set_config_mock:
            del opts['extra_opts']
            self.assertEqual(snapper.create_config(**opts),
                             DBUS_RET['ListConfigs'][0])
            assert not set_config_mock.called
            self.assertRaises(CommandExecutionError, snapper.create_config)

    @patch('salt.modules.snapper.snapper.CreateSingleSnapshot',
           MagicMock(return_value=1234))
    @patch('salt.modules.snapper.snapper.CreatePreSnapshot',
           MagicMock(return_value=1234))
    @patch('salt.modules.snapper.snapper.CreatePostSnapshot',
           MagicMock(return_value=1234))
    def test_create_snapshot(self):
        for snapshot_type in ['pre', 'post', 'single']:
            opts = {
                '__pub_jid': 20160607130930720112,
                'type': snapshot_type,
                'description': 'Test description',
                'cleanup_algorithm': 'number',
                'pre_number': 23,
            }
            self.assertEqual(snapper.create_snapshot(**opts), 1234)

    @patch('salt.modules.snapper.snapper.DeleteSnapshots', MagicMock())
    @patch('salt.modules.snapper.snapper.ListSnapshots',
           MagicMock(return_value=DBUS_RET['ListSnapshots']))
    def test_delete_snapshot_id_success(self):
        self.assertEqual(snapper.delete_snapshot(snapshots_ids=43),
                         {"root": {
                             "ids": [43],
                             "status": "deleted"
                         }})
        self.assertEqual(snapper.delete_snapshot(snapshots_ids=[42, 43]),
                         {"root": {
                             "ids": [42, 43],
                             "status": "deleted"
                         }})

    @patch('salt.modules.snapper.snapper.DeleteSnapshots', MagicMock())
    @patch('salt.modules.snapper.snapper.ListSnapshots',
           MagicMock(return_value=DBUS_RET['ListSnapshots']))
    def test_delete_snapshot_id_fail(self):
        self.assertRaises(CommandExecutionError, snapper.delete_snapshot)
        self.assertRaises(CommandExecutionError,
                          snapper.delete_snapshot,
                          snapshots_ids=1)
        self.assertRaises(CommandExecutionError,
                          snapper.delete_snapshot,
                          snapshots_ids=[1, 2])

    @patch('salt.modules.snapper.snapper.SetSnapshot', MagicMock())
    def test_modify_snapshot(self):
        _ret = {
            'userdata': {
                'userdata2': 'uservalue2'
            },
            'description': 'UPDATED DESCRIPTION',
            'timestamp': 1457006571,
            'cleanup': 'number',
            'user': '******',
            'type': 'pre',
            'id': 42
        }
        _opts = {
            'config': 'root',
            'snapshot_id': 42,
            'cleanup': 'number',
            'description': 'UPDATED DESCRIPTION',
            'userdata': {
                'userdata2': 'uservalue2'
            },
        }
        with patch(
                'salt.modules.snapper.get_snapshot',
                MagicMock(side_effect=[DBUS_RET['ListSnapshots'][0], _ret])):
            self.assertDictEqual(snapper.modify_snapshot(**_opts), _ret)

    @patch('salt.modules.snapper._get_last_snapshot',
           MagicMock(return_value={'id': 42}))
    def test__get_num_interval(self):
        self.assertEqual(
            snapper._get_num_interval(config=None, num_pre=None,
                                      num_post=None), (42, 0))  # pylint: disable=protected-access
        self.assertEqual(
            snapper._get_num_interval(config=None, num_pre=None, num_post=50),
            (42, 50))  # pylint: disable=protected-access
        self.assertEqual(
            snapper._get_num_interval(config=None, num_pre=42, num_post=50),
            (42, 50))  # pylint: disable=protected-access

    def test_run(self):
        patch_dict = {
            'snapper.create_snapshot': MagicMock(return_value=43),
            'test.ping': MagicMock(return_value=True),
        }
        with patch.dict(snapper.__salt__, patch_dict):
            self.assertEqual(snapper.run("test.ping"), True)
            self.assertRaises(CommandExecutionError, snapper.run,
                              "unknown.func")

    @patch('salt.modules.snapper._get_num_interval',
           MagicMock(return_value=(42, 43)))
    @patch('salt.modules.snapper.snapper.GetComparison', MagicMock())
    @patch('salt.modules.snapper.snapper.GetFiles',
           MagicMock(return_value=DBUS_RET['GetFiles']))
    @patch('salt.modules.snapper.snapper.ListConfigs',
           MagicMock(return_value=DBUS_RET['ListConfigs']))
    def test_status(self):
        if six.PY3:
            self.assertCountEqual(snapper.status(), MODULE_RET['GETFILES'])
            self.assertCountEqual(snapper.status(num_pre="42", num_post=43),
                                  MODULE_RET['GETFILES'])
            self.assertCountEqual(snapper.status(num_pre=42),
                                  MODULE_RET['GETFILES'])
            self.assertCountEqual(snapper.status(num_post=43),
                                  MODULE_RET['GETFILES'])
        else:
            self.assertItemsEqual(snapper.status(), MODULE_RET['GETFILES'])
            self.assertItemsEqual(snapper.status(num_pre="42", num_post=43),
                                  MODULE_RET['GETFILES'])
            self.assertItemsEqual(snapper.status(num_pre=42),
                                  MODULE_RET['GETFILES'])
            self.assertItemsEqual(snapper.status(num_post=43),
                                  MODULE_RET['GETFILES'])

    @patch('salt.modules.snapper.status',
           MagicMock(return_value=MODULE_RET['GETFILES']))
    def test_changed_files(self):
        self.assertEqual(snapper.changed_files(),
                         MODULE_RET['GETFILES'].keys())

    @patch('salt.modules.snapper._get_num_interval',
           MagicMock(return_value=(42, 43)))
    @patch('salt.modules.snapper.status',
           MagicMock(return_value=MODULE_RET['GETFILES']))
    def test_undo(self):
        cmd_ret = 'create:0 modify:1 delete:0'
        with patch.dict(snapper.__salt__,
                        {'cmd.run': MagicMock(return_value=cmd_ret)}):
            module_ret = {'create': '0', 'delete': '0', 'modify': '1'}
            self.assertEqual(snapper.undo(files=['/tmp/foo']), module_ret)

        cmd_ret = 'create:1 modify:1 delete:0'
        with patch.dict(snapper.__salt__,
                        {'cmd.run': MagicMock(return_value=cmd_ret)}):
            module_ret = {'create': '1', 'delete': '0', 'modify': '1'}
            self.assertEqual(snapper.undo(files=['/tmp/foo', '/tmp/foo2']),
                             module_ret)

        cmd_ret = 'create:1 modify:1 delete:1'
        with patch.dict(snapper.__salt__,
                        {'cmd.run': MagicMock(return_value=cmd_ret)}):
            module_ret = {'create': '1', 'delete': '1', 'modify': '1'}
            self.assertEqual(
                snapper.undo(files=['/tmp/foo', '/tmp/foo2', '/tmp/foo3']),
                module_ret)

    @patch('salt.modules.snapper.list_snapshots',
           MagicMock(return_value=MODULE_RET['SNAPSHOTS']))
    def test__get_jid_snapshots(self):
        self.assertEqual(
            snapper._get_jid_snapshots("20160607130930720112"),  # pylint: disable=protected-access
            (MODULE_RET['SNAPSHOTS'][0]['id'],
             MODULE_RET['SNAPSHOTS'][1]['id']))

    @patch('salt.modules.snapper._get_jid_snapshots',
           MagicMock(return_value=(42, 43)))
    @patch('salt.modules.snapper.undo',
           MagicMock(return_value='create:1 modify:1 delete:1'))
    def test_undo_jid(self):
        self.assertEqual(snapper.undo_jid(20160607130930720112),
                         'create:1 modify:1 delete:1')

    @patch('salt.modules.snapper._get_num_interval',
           MagicMock(return_value=(42, 43)))
    @patch('salt.modules.snapper.snapper.MountSnapshot',
           MagicMock(side_effect=["/.snapshots/55/snapshot", ""]))
    @patch('salt.modules.snapper.snapper.UmountSnapshot',
           MagicMock(return_value=""))
    @patch('os.path.isdir', MagicMock(return_value=False))
    @patch('salt.modules.snapper.changed_files',
           MagicMock(return_value=["/tmp/foo2"]))
    @patch('salt.modules.snapper._is_text_file', MagicMock(return_value=True))
    @patch('os.path.isfile', MagicMock(side_effect=[False, True]))
    @patch('salt.utils.fopen',
           mock_open(read_data=FILE_CONTENT["/tmp/foo2"]['post']))
    @patch('salt.modules.snapper.snapper.ListConfigs',
           MagicMock(return_value=DBUS_RET['ListConfigs']))
    def test_diff_text_file(self):
        if sys.version_info < (2, 7):
            self.assertEqual(snapper.diff(),
                             {"/tmp/foo2": MODULE_RET['DIFF']['/tmp/foo26']})
        else:
            self.assertEqual(snapper.diff(),
                             {"/tmp/foo2": MODULE_RET['DIFF']['/tmp/foo2']})

    @patch('salt.modules.snapper._get_num_interval',
           MagicMock(return_value=(55, 0)))
    @patch('salt.modules.snapper.snapper.MountSnapshot',
           MagicMock(side_effect=[
               "/.snapshots/55/snapshot", "", "/.snapshots/55/snapshot", ""
           ]))
    @patch('salt.modules.snapper.snapper.UmountSnapshot',
           MagicMock(return_value=""))
    @patch('salt.modules.snapper.changed_files',
           MagicMock(return_value=["/tmp/foo", "/tmp/foo2"]))
    @patch('salt.modules.snapper._is_text_file', MagicMock(return_value=True))
    @patch('os.path.isfile', MagicMock(side_effect=[True, True, False, True]))
    @patch('os.path.isdir', MagicMock(return_value=False))
    @patch('salt.modules.snapper.snapper.ListConfigs',
           MagicMock(return_value=DBUS_RET['ListConfigs']))
    @skipIf(sys.version_info < (2, 7),
            'Python 2.7 required to compare diff properly')
    def test_diff_text_files(self):
        fopen_effect = [
            mock_open(read_data=FILE_CONTENT["/tmp/foo"]['pre']).return_value,
            mock_open(read_data=FILE_CONTENT["/tmp/foo"]['post']).return_value,
            mock_open(
                read_data=FILE_CONTENT["/tmp/foo2"]['post']).return_value,
        ]
        with patch('salt.utils.fopen') as fopen_mock:
            fopen_mock.side_effect = fopen_effect
            module_ret = {
                "/tmp/foo": MODULE_RET['DIFF']["/tmp/foo"],
                "/tmp/foo2": MODULE_RET['DIFF']["/tmp/foo2"],
            }
            self.assertEqual(snapper.diff(), module_ret)

    @patch('salt.modules.snapper._get_num_interval',
           MagicMock(return_value=(55, 0)))
    @patch('salt.modules.snapper.snapper.MountSnapshot',
           MagicMock(side_effect=[
               "/.snapshots/55/snapshot", "", "/.snapshots/55/snapshot", ""
           ]))
    @patch('salt.modules.snapper.snapper.UmountSnapshot',
           MagicMock(return_value=""))
    @patch('salt.modules.snapper.changed_files',
           MagicMock(return_value=["/tmp/foo3"]))
    @patch('salt.modules.snapper._is_text_file', MagicMock(return_value=False))
    @patch('os.path.isfile', MagicMock(side_effect=[True, True]))
    @patch('os.path.isdir', MagicMock(return_value=False))
    @patch.dict(
        snapper.__salt__, {
            'hashutil.sha256_digest':
            MagicMock(side_effect=[
                "e61f8b762d83f3b4aeb3689564b0ffbe54fa731a69a1e208dc9440ce0f69d19b",
                "f18f971f1517449208a66589085ddd3723f7f6cefb56c141e3d97ae49e1d87fa",
            ])
        })
    @patch('salt.modules.snapper.snapper.ListConfigs',
           MagicMock(return_value=DBUS_RET['ListConfigs']))
    def test_diff_binary_files(self):
        fopen_effect = [
            mock_open(read_data="dummy binary").return_value,
            mock_open(read_data="dummy binary").return_value,
        ]
        with patch('salt.utils.fopen') as fopen_mock:
            fopen_mock.side_effect = fopen_effect
            module_ret = {
                "/tmp/foo3": MODULE_RET['DIFF']["/tmp/foo3"],
            }
            self.assertEqual(snapper.diff(), module_ret)