Changeset View
Changeset View
Standalone View
Standalone View
swh/storage/tests/test_retry.py
| # Copyright (C) 2020 The Software Heritage developers | # Copyright (C) 2020 The Software Heritage developers | ||||
| # See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
| # License: GNU General Public License version 3, or any later version | # License: GNU General Public License version 3, or any later version | ||||
| # See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
| from typing import Dict | |||||
| from unittest.mock import call | from unittest.mock import call | ||||
| import psycopg2 | import psycopg2 | ||||
| import pytest | import pytest | ||||
| from swh.model.model import ( | from swh.model.model import ( | ||||
| Content, | Content, | ||||
| Directory, | Directory, | ||||
| ▲ Show 20 Lines • Show All 401 Lines • ▼ Show 20 Lines | ): | ||||
| with pytest.raises(StorageArgumentException, match="Refuse to add"): | with pytest.raises(StorageArgumentException, match="Refuse to add"): | ||||
| swh_storage.origin_visit_add(origin_url, date_visit1, "svn") | swh_storage.origin_visit_add(origin_url, date_visit1, "svn") | ||||
| mock_memory.assert_has_calls( | mock_memory.assert_has_calls( | ||||
| [call(origin_url, date_visit1, "svn"),] | [call(origin_url, date_visit1, "svn"),] | ||||
| ) | ) | ||||
| def test_retrying_proxy_storage_tool_add(swh_storage, sample_data): | def test_retrying_proxy_storage_metadata_fetcher_add(swh_storage, sample_data): | ||||
| """Standard tool_add works as before | """Standard metadata_fetcher_add works as before | ||||
| """ | """ | ||||
| sample_tool = sample_data["tool"][0] | fetcher = sample_data["fetcher"][0] | ||||
| tool = swh_storage.tool_get(sample_tool) | metadata_fetcher = swh_storage.metadata_fetcher_get( | ||||
| assert not tool | fetcher["name"], fetcher["version"] | ||||
| ) | |||||
| assert not metadata_fetcher | |||||
| tools = swh_storage.tool_add([sample_tool]) | swh_storage.metadata_fetcher_add(**fetcher) | ||||
| assert tools | |||||
| tool = tools[0] | |||||
| tool.pop("id") | |||||
| assert tool == sample_tool | |||||
| tool = swh_storage.tool_get(sample_tool) | actual_fetcher = swh_storage.metadata_fetcher_get( | ||||
| tool.pop("id") | fetcher["name"], fetcher["version"] | ||||
| assert tool == sample_tool | ) | ||||
| assert actual_fetcher == fetcher | |||||
| def test_retrying_proxy_storage_tool_add_with_retry( | def test_retrying_proxy_storage_metadata_fetcher_add_with_retry( | ||||
| monkeypatch_sleep, swh_storage, sample_data, mocker, fake_hash_collision | monkeypatch_sleep, swh_storage, sample_data, mocker, fake_hash_collision | ||||
| ): | ): | ||||
| """Multiple retries for hash collision and psycopg2 error but finally ok | """Multiple retries for hash collision and psycopg2 error but finally ok | ||||
| """ | """ | ||||
| sample_tool = sample_data["tool"][0] | fetcher = sample_data["fetcher"][0] | ||||
| mock_memory = mocker.patch("swh.storage.in_memory.InMemoryStorage.tool_add") | mock_memory = mocker.patch( | ||||
| "swh.storage.in_memory.InMemoryStorage.metadata_fetcher_add" | |||||
| ) | |||||
| mock_memory.side_effect = [ | mock_memory.side_effect = [ | ||||
| # first try goes ko | # first try goes ko | ||||
| fake_hash_collision, | fake_hash_collision, | ||||
| # second try goes ko | # second try goes ko | ||||
| psycopg2.IntegrityError("tool already inserted"), | psycopg2.IntegrityError("metadata_fetcher already inserted"), | ||||
| # ok then! | # ok then! | ||||
| [sample_tool], | [fetcher], | ||||
| ] | ] | ||||
| tool = swh_storage.tool_get(sample_tool) | actual_fetcher = swh_storage.metadata_fetcher_get( | ||||
| assert not tool | fetcher["name"], fetcher["version"] | ||||
| ) | |||||
| assert not actual_fetcher | |||||
| tools = swh_storage.tool_add([sample_tool]) | swh_storage.metadata_fetcher_add(**fetcher) | ||||
| assert tools == [sample_tool] | |||||
| mock_memory.assert_has_calls( | mock_memory.assert_has_calls( | ||||
| [call([sample_tool]), call([sample_tool]), call([sample_tool]),] | [ | ||||
| call(fetcher["name"], fetcher["version"], fetcher["metadata"]), | |||||
| call(fetcher["name"], fetcher["version"], fetcher["metadata"]), | |||||
| call(fetcher["name"], fetcher["version"], fetcher["metadata"]), | |||||
| ] | |||||
| ) | ) | ||||
| def test_retrying_proxy_swh_storage_tool_add_failure(swh_storage, sample_data, mocker): | def test_retrying_proxy_swh_storage_metadata_fetcher_add_failure( | ||||
| swh_storage, sample_data, mocker | |||||
| ): | |||||
| """Unfiltered errors are raising without retry | """Unfiltered errors are raising without retry | ||||
| """ | """ | ||||
| mock_memory = mocker.patch("swh.storage.in_memory.InMemoryStorage.tool_add") | mock_memory = mocker.patch( | ||||
| mock_memory.side_effect = StorageArgumentException("Refuse to add tool always!") | "swh.storage.in_memory.InMemoryStorage.metadata_fetcher_add" | ||||
| ) | |||||
| mock_memory.side_effect = StorageArgumentException( | |||||
| "Refuse to add metadata_fetcher always!" | |||||
| ) | |||||
| sample_tool = sample_data["tool"][0] | fetcher = sample_data["fetcher"][0] | ||||
| tool = swh_storage.tool_get(sample_tool) | actual_fetcher = swh_storage.metadata_fetcher_get( | ||||
| assert not tool | fetcher["name"], fetcher["version"] | ||||
| ) | |||||
| assert not actual_fetcher | |||||
| with pytest.raises(StorageArgumentException, match="Refuse to add"): | with pytest.raises(StorageArgumentException, match="Refuse to add"): | ||||
| swh_storage.tool_add([sample_tool]) | swh_storage.metadata_fetcher_add(**fetcher) | ||||
| assert mock_memory.call_count == 1 | assert mock_memory.call_count == 1 | ||||
| def to_provider(provider: Dict) -> Dict: | def test_retrying_proxy_storage_metadata_authority_add(swh_storage, sample_data): | ||||
| return { | """Standard metadata_authority_add works as before | ||||
| "provider_name": provider["name"], | |||||
| "provider_url": provider["url"], | |||||
| "provider_type": provider["type"], | |||||
| "metadata": provider["metadata"], | |||||
| } | |||||
| def test_retrying_proxy_storage_metadata_provider_add(swh_storage, sample_data): | |||||
| """Standard metadata_provider_add works as before | |||||
| """ | """ | ||||
| provider = sample_data["provider"][0] | authority = sample_data["authority"][0] | ||||
| provider_get = to_provider(provider) | |||||
| provider = swh_storage.metadata_provider_get_by(provider_get) | assert not swh_storage.metadata_authority_get(authority["type"], authority["url"]) | ||||
| assert not provider | |||||
| provider_id = swh_storage.metadata_provider_add(**provider_get) | swh_storage.metadata_authority_add(**authority) | ||||
| assert provider_id | |||||
| actual_provider = swh_storage.metadata_provider_get(provider_id) | actual_authority = swh_storage.metadata_authority_get( | ||||
| assert actual_provider | authority["type"], authority["url"] | ||||
| actual_provider_id = actual_provider.pop("id") | ) | ||||
| assert actual_provider_id == provider_id | assert actual_authority == authority | ||||
| assert actual_provider == provider_get | |||||
| def test_retrying_proxy_storage_metadata_provider_add_with_retry( | def test_retrying_proxy_storage_metadata_authority_add_with_retry( | ||||
| monkeypatch_sleep, swh_storage, sample_data, mocker, fake_hash_collision | monkeypatch_sleep, swh_storage, sample_data, mocker, fake_hash_collision | ||||
| ): | ): | ||||
| """Multiple retries for hash collision and psycopg2 error but finally ok | """Multiple retries for hash collision and psycopg2 error but finally ok | ||||
| """ | """ | ||||
| provider = sample_data["provider"][0] | authority = sample_data["authority"][0] | ||||
| provider_get = to_provider(provider) | |||||
| mock_memory = mocker.patch( | mock_memory = mocker.patch( | ||||
| "swh.storage.in_memory.InMemoryStorage.metadata_provider_add" | "swh.storage.in_memory.InMemoryStorage.metadata_authority_add" | ||||
| ) | ) | ||||
| mock_memory.side_effect = [ | mock_memory.side_effect = [ | ||||
| # first try goes ko | # first try goes ko | ||||
| fake_hash_collision, | fake_hash_collision, | ||||
| # second try goes ko | # second try goes ko | ||||
| psycopg2.IntegrityError("provider_id already inserted"), | psycopg2.IntegrityError("foo bar"), | ||||
| # ok then! | # ok then! | ||||
| "provider_id", | None, | ||||
| ] | ] | ||||
ardumont: can you please merge the string, that's black doing some joke on us? | |||||
| provider = swh_storage.metadata_provider_get_by(provider_get) | assert not swh_storage.metadata_authority_get(authority["type"], authority["url"]) | ||||
| assert not provider | |||||
| provider_id = swh_storage.metadata_provider_add(**provider_get) | swh_storage.metadata_authority_add(**authority) | ||||
| assert provider_id == "provider_id" | |||||
| provider_arg_names = ("provider_name", "provider_type", "provider_url", "metadata") | authority_arg_names = ("type", "url", "metadata") | ||||
| provider_args = [provider_get[key] for key in provider_arg_names] | authority_args = [authority[key] for key in authority_arg_names] | ||||
| mock_memory.assert_has_calls( | mock_memory.assert_has_calls( | ||||
| [call(*provider_args), call(*provider_args), call(*provider_args),] | [call(*authority_args), call(*authority_args), call(*authority_args),] | ||||
| ) | ) | ||||
| def test_retrying_proxy_swh_storage_metadata_provider_add_failure( | def test_retrying_proxy_swh_storage_metadata_authority_add_failure( | ||||
| swh_storage, sample_data, mocker | swh_storage, sample_data, mocker | ||||
| ): | ): | ||||
| """Unfiltered errors are raising without retry | """Unfiltered errors are raising without retry | ||||
| """ | """ | ||||
| mock_memory = mocker.patch( | mock_memory = mocker.patch( | ||||
| "swh.storage.in_memory.InMemoryStorage.metadata_provider_add" | "swh.storage.in_memory.InMemoryStorage.metadata_authority_add" | ||||
| ) | ) | ||||
| mock_memory.side_effect = StorageArgumentException( | mock_memory.side_effect = StorageArgumentException( | ||||
| "Refuse to add provider_id always!" | "Refuse to add authority_id always!" | ||||
| ) | ) | ||||
| provider = sample_data["provider"][0] | authority = sample_data["authority"][0] | ||||
| provider_get = to_provider(provider) | |||||
| provider_id = swh_storage.metadata_provider_get_by(provider_get) | swh_storage.metadata_authority_get(authority["type"], authority["url"]) | ||||
| assert not provider_id | |||||
| with pytest.raises(StorageArgumentException, match="Refuse to add"): | with pytest.raises(StorageArgumentException, match="Refuse to add"): | ||||
| swh_storage.metadata_provider_add(**provider_get) | swh_storage.metadata_authority_add(**authority) | ||||
| assert mock_memory.call_count == 1 | assert mock_memory.call_count == 1 | ||||
| def test_retrying_proxy_storage_origin_metadata_add(swh_storage, sample_data): | def test_retrying_proxy_storage_origin_metadata_add(swh_storage, sample_data): | ||||
| """Standard origin_metadata_add works as before | """Standard origin_metadata_add works as before | ||||
| """ | """ | ||||
| ori_meta = sample_data["origin_metadata"][0] | ori_meta = sample_data["origin_metadata"][0] | ||||
| origin = ori_meta["origin"] | swh_storage.origin_add_one({"url": ori_meta["origin_url"]}) | ||||
| swh_storage.origin_add_one(origin) | swh_storage.metadata_authority_add(**sample_data["authority"][0]) | ||||
| provider_get = to_provider(ori_meta["provider"]) | swh_storage.metadata_fetcher_add(**sample_data["fetcher"][0]) | ||||
| provider_id = swh_storage.metadata_provider_add(**provider_get) | |||||
| origin_metadata = swh_storage.origin_metadata_get_by(origin["url"]) | origin_metadata = swh_storage.origin_metadata_get( | ||||
| ori_meta["origin_url"], ori_meta["authority"] | |||||
| ) | |||||
| assert not origin_metadata | assert not origin_metadata | ||||
| swh_storage.origin_metadata_add( | swh_storage.origin_metadata_add(**ori_meta) | ||||
| origin["url"], | |||||
| ori_meta["discovery_date"], | |||||
| provider_id, | |||||
| ori_meta["tool"], | |||||
| ori_meta["metadata"], | |||||
| ) | |||||
| origin_metadata = swh_storage.origin_metadata_get_by(origin["url"]) | origin_metadata = swh_storage.origin_metadata_get( | ||||
| ori_meta["origin_url"], ori_meta["authority"] | |||||
| ) | |||||
| assert origin_metadata | assert origin_metadata | ||||
| def test_retrying_proxy_storage_origin_metadata_add_with_retry( | def test_retrying_proxy_storage_origin_metadata_add_with_retry( | ||||
| monkeypatch_sleep, swh_storage, sample_data, mocker, fake_hash_collision | monkeypatch_sleep, swh_storage, sample_data, mocker, fake_hash_collision | ||||
| ): | ): | ||||
| """Multiple retries for hash collision and psycopg2 error but finally ok | """Multiple retries for hash collision and psycopg2 error but finally ok | ||||
| """ | """ | ||||
| ori_meta = sample_data["origin_metadata"][0] | ori_meta = sample_data["origin_metadata"][0] | ||||
| origin = ori_meta["origin"] | swh_storage.origin_add_one({"url": ori_meta["origin_url"]}) | ||||
| swh_storage.origin_add_one(origin) | swh_storage.metadata_authority_add(**sample_data["authority"][0]) | ||||
| provider_get = to_provider(ori_meta["provider"]) | swh_storage.metadata_fetcher_add(**sample_data["fetcher"][0]) | ||||
| provider_id = swh_storage.metadata_provider_add(**provider_get) | |||||
| mock_memory = mocker.patch( | mock_memory = mocker.patch( | ||||
| "swh.storage.in_memory.InMemoryStorage.origin_metadata_add" | "swh.storage.in_memory.InMemoryStorage.origin_metadata_add" | ||||
| ) | ) | ||||
| mock_memory.side_effect = [ | mock_memory.side_effect = [ | ||||
| # first try goes ko | # first try goes ko | ||||
| fake_hash_collision, | fake_hash_collision, | ||||
| # second try goes ko | # second try goes ko | ||||
| psycopg2.IntegrityError("provider_id already inserted"), | psycopg2.IntegrityError("foo bar"), | ||||
| # ok then! | # ok then! | ||||
| None, | None, | ||||
| ] | ] | ||||
| url = origin["url"] | |||||
| ts = ori_meta["discovery_date"] | |||||
| tool_id = ori_meta["tool"] | |||||
| metadata = ori_meta["metadata"] | |||||
| # No exception raised as insertion finally came through | # No exception raised as insertion finally came through | ||||
| swh_storage.origin_metadata_add(url, ts, provider_id, tool_id, metadata) | swh_storage.origin_metadata_add(**ori_meta) | ||||
| mock_memory.assert_has_calls( | mock_memory.assert_has_calls( | ||||
| [ # 3 calls, as long as error raised | [ # 3 calls, as long as error raised | ||||
| call(url, ts, provider_id, tool_id, metadata), | call( | ||||
| call(url, ts, provider_id, tool_id, metadata), | ori_meta["origin_url"], | ||||
| call(url, ts, provider_id, tool_id, metadata), | ori_meta["discovery_date"], | ||||
| ori_meta["authority"], | |||||
| ori_meta["fetcher"], | |||||
| ori_meta["format"], | |||||
| ori_meta["metadata"], | |||||
| ), | |||||
| call( | |||||
| ori_meta["origin_url"], | |||||
| ori_meta["discovery_date"], | |||||
| ori_meta["authority"], | |||||
| ori_meta["fetcher"], | |||||
| ori_meta["format"], | |||||
| ori_meta["metadata"], | |||||
| ), | |||||
| call( | |||||
| ori_meta["origin_url"], | |||||
| ori_meta["discovery_date"], | |||||
| ori_meta["authority"], | |||||
| ori_meta["fetcher"], | |||||
| ori_meta["format"], | |||||
| ori_meta["metadata"], | |||||
| ), | |||||
| ] | ] | ||||
| ) | ) | ||||
| def test_retrying_proxy_swh_storage_origin_metadata_add_failure( | def test_retrying_proxy_swh_storage_origin_metadata_add_failure( | ||||
| swh_storage, sample_data, mocker | swh_storage, sample_data, mocker | ||||
| ): | ): | ||||
| """Unfiltered errors are raising without retry | """Unfiltered errors are raising without retry | ||||
| """ | """ | ||||
| mock_memory = mocker.patch( | mock_memory = mocker.patch( | ||||
| "swh.storage.in_memory.InMemoryStorage.origin_metadata_add" | "swh.storage.in_memory.InMemoryStorage.origin_metadata_add" | ||||
| ) | ) | ||||
| mock_memory.side_effect = StorageArgumentException("Refuse to add always!") | mock_memory.side_effect = StorageArgumentException("Refuse to add always!") | ||||
| ori_meta = sample_data["origin_metadata"][0] | ori_meta = sample_data["origin_metadata"][0] | ||||
| origin = ori_meta["origin"] | swh_storage.origin_add_one({"url": ori_meta["origin_url"]}) | ||||
| swh_storage.origin_add_one(origin) | |||||
| url = origin["url"] | |||||
| ts = ori_meta["discovery_date"] | |||||
| provider_id = "provider_id" | |||||
| tool_id = ori_meta["tool"] | |||||
| metadata = ori_meta["metadata"] | |||||
| with pytest.raises(StorageArgumentException, match="Refuse to add"): | with pytest.raises(StorageArgumentException, match="Refuse to add"): | ||||
| swh_storage.origin_metadata_add(url, ts, provider_id, tool_id, metadata) | swh_storage.origin_metadata_add(**ori_meta) | ||||
| assert mock_memory.call_count == 1 | assert mock_memory.call_count == 1 | ||||
| def test_retrying_proxy_swh_storage_origin_visit_update(swh_storage, sample_data): | def test_retrying_proxy_swh_storage_origin_visit_update(swh_storage, sample_data): | ||||
| """Standard origin_visit_update works as before | """Standard origin_visit_update works as before | ||||
| """ | """ | ||||
| ▲ Show 20 Lines • Show All 365 Lines • Show Last 20 Lines | |||||
can you please merge the string, that's black doing some joke on us?