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()}}
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()}}
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'))
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)
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" )
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)