def test_only_print_queries(model_name, config, monkeypatch, caplog): """ Test that if --only-print-queries is passed, the SQL query is printed but no deletions or simulation occurs. """ caplog.set_level('INFO') delete_mock = mock.Mock() monkeypatch.setattr(QuerySet, 'delete', delete_mock) command = delete_old_records.Command() model = apps.get_model(model_name) mapping = MAPPING[model_name] model_factory = mapping['factory'] for _ in range(3): _create_model_obj(model_factory, **mapping['expired_objects_kwargs'][0]) management.call_command(command, model_name, only_print_queries=True) assert not delete_mock.called log_text = caplog.text.lower() assert f'{model._meta.verbose_name_plural} to delete:' in log_text for relation in get_relations_to_delete(model): related_meta = relation.related_model._meta expected_related_log = ( f'{related_meta.verbose_name_plural} to delete ' f'(via {related_meta.model_name}.{relation.remote_field.name}): ' ).lower() assert expected_related_log in log_text assert f'from "{related_meta.db_table}"' in log_text
def test_simulate( model_name, config, track_return_values, es_with_signals, es_collector_context_manager, ): """ Test that if --simulate is passed in, the command only simulates the action without making any actual changes. """ # Set up the state before running the command delete_return_value_tracker = track_return_values(QuerySet, 'delete') command = delete_old_records.Command() mapping = MAPPING[model_name] model_factory = mapping['factory'] has_search_app = not mapping.get('has_no_search_app') with es_collector_context_manager as collector: for _ in range(3): _create_model_obj(model_factory, **mapping['expired_objects_kwargs'][0]) collector.flush_and_refresh() model = apps.get_model(model_name) if has_search_app: search_app = get_search_app_by_model(model) read_alias = search_app.es_model.get_read_alias() assert es_with_signals.count(read_alias, doc_type=search_app.name)['count'] == 3 assert model.objects.count() == 3 # Run the command management.call_command(command, model_name, simulate=True) es_with_signals.indices.refresh() # Check which models were deleted prior to the rollback return_values = delete_return_value_tracker.return_values assert len(return_values) == 1 _, deletions_by_model = return_values[0] actual_deleted_models = { # only include models actually deleted deleted_model for deleted_model, deleted_count in deletions_by_model.items() if deleted_count } assert model._meta.label in {model._meta.label} assert actual_deleted_models - {model._meta.label } <= mapping['implicitly_deletable_models'] assert deletions_by_model[model._meta.label] == 3 # Check that nothing has actually been deleted assert model.objects.count() == 3 if has_search_app: assert es_with_signals.count(read_alias, doc_type=search_app.name)['count'] == 3
def test_with_opensearch_exception(mocked_bulk): """ Test that if OpenSearch returns a 5xx error, the command completes but it also raises a DataHubError with details of the error. """ mocked_bulk.return_value = (None, [{'delete': {'status': 500}}]) command = delete_old_records.Command() model_name = next(iter(delete_old_records.Command.CONFIGS)) mapping = MAPPING[model_name] model_factory = MAPPING[model_name]['factory'] _create_model_obj(model_factory, **mapping['expired_objects_kwargs'][0]) with pytest.raises(DataHubError): management.call_command(command, model_name) model = apps.get_model(model_name) assert model.objects.count() == 0
def test_run( model_label, factory_kwargs, relation_mapping, relation_factory_kwargs, is_expired, track_return_values, opensearch_with_signals, opensearch_collector_context_manager, ): """Tests the delete_old_records commands for various cases specified by MAPPING above.""" # Set up the state before running the command mapping = MAPPING[model_label] model_factory = mapping['factory'] command = delete_old_records.Command() model = apps.get_model(model_label) has_search_app = not mapping.get('has_no_search_app') delete_return_value_tracker = track_return_values(QuerySet, 'delete') with opensearch_collector_context_manager as collector: obj = _create_model_obj(model_factory, **factory_kwargs) total_model_records = 1 if relation_mapping: relation_model = relation_mapping['factory']._meta.get_model_class( ) relation_field = relation_model._meta.get_field( relation_mapping['field']) relation_factory_arg = [obj ] if relation_field.many_to_many else obj _create_model_obj( relation_mapping['factory'], **relation_factory_kwargs, **{relation_mapping['field']: relation_factory_arg}, ) if relation_mapping['factory']._meta.get_model_class() is model: total_model_records += 1 collector.flush_and_refresh() num_expired_records = 1 if is_expired else 0 if has_search_app: search_app = get_search_app_by_model(model) read_alias = search_app.search_model.get_read_alias() assert opensearch_with_signals.count( index=read_alias)['count'] == total_model_records assert model.objects.count() == total_model_records # Run the command management.call_command(command, model_label) opensearch_with_signals.indices.refresh() # Check if the object has been deleted assert model.objects.count() == total_model_records - num_expired_records if has_search_app: assert opensearch_with_signals.count( index=read_alias)['count'] == (total_model_records - num_expired_records) # Check which models were actually deleted return_values = delete_return_value_tracker.return_values assert len(return_values) == 1 _, deletions_by_model = return_values[0] if is_expired: assert deletions_by_model[model._meta.label] == num_expired_records assert model._meta.label in {model._meta.label} actual_deleted_models = { # only include models actually deleted deleted_model for deleted_model, deleted_count in deletions_by_model.items() if deleted_count } assert actual_deleted_models - {model._meta.label } <= mapping['implicitly_deletable_models']
def test_run( model_label, factory_kwargs, relation_mapping, relation_factory_kwargs, is_expired, track_return_values, setup_es, ): """Tests the delete_old_records commands for various cases specified by MAPPING above.""" mapping = MAPPING[model_label] model_factory = mapping['factory'] command = delete_old_records.Command() model = apps.get_model(model_label) delete_return_value_tracker = track_return_values(QuerySet, 'delete') obj = _create_model_obj(model_factory, **factory_kwargs) total_model_records = 1 if relation_mapping: relation_model = relation_mapping['factory']._meta.get_model_class() relation_field = relation_model._meta.get_field( relation_mapping['field']) relation_factory_arg = [obj] if relation_field.many_to_many else obj _create_model_obj( relation_mapping['factory'], **relation_factory_kwargs, **{relation_mapping['field']: relation_factory_arg}, ) if relation_mapping['factory']._meta.get_model_class() is model: total_model_records += 1 num_expired_records = 1 if is_expired else 0 search_app = get_search_app_by_model(model) doc_type = search_app.name read_alias = search_app.es_model.get_read_alias() setup_es.indices.refresh() assert model.objects.count() == total_model_records assert setup_es.count(read_alias, doc_type=doc_type)['count'] == total_model_records management.call_command(command, model_label) setup_es.indices.refresh() # Check if the object has been deleted assert model.objects.count() == total_model_records - num_expired_records assert setup_es.count(read_alias, doc_type=doc_type)['count'] == (total_model_records - num_expired_records) # Check which models were actually deleted return_values = delete_return_value_tracker.return_values assert len(return_values) == 1 _, deletions_by_model = return_values[0] if is_expired: assert deletions_by_model[model._meta.label] == num_expired_records assert model._meta.label in {model._meta.label} actual_deleted_models = { # only include models actually deleted deleted_model for deleted_model, deleted_count in deletions_by_model.items() if deleted_count } assert actual_deleted_models - {model._meta.label } <= mapping['implicitly_deletable_models']