Repository: CS-SI/eodag
Pull request #486 (2022-07-20 16:06:49)

fix: discover_product_types auth
Fixes issue with `discover_product_types()` that did not use configured auth plugin to query on provider's endpoint

github-actions[bot]: <strong> </strong>

| File | Coverage |   |
| - | :-: | :-: |
| **All files** | `80%` | :white_check_mark: |
| eodag/api/core.py | `88%` | :white_check_mark: |
| eodag/plugins/search/qssearch.py | `74%` | :white_check_mark: |

<strong> </strong>

| File | Coverage |   |
| - | :-: | :-: |
| **All files** | `80%` | :white_check_mark: |
| eodag/api/core.py | `88%` | :white_check_mark: |
| eodag/plugins/search/qssearch.py | `74%` | :white_check_mark: |
| eodag/api/core.py | `88%` | :white_check_mark: |
| eodag/plugins/search/qssearch.py | `74%` | :white_check_mark: |

_Minimum allowed coverage is `70%`_

<p align="right">Generated by :monkey: cobertura-action against 070e4669674eced070b28c7c728fe3b03930d1c6 </p>
github-actions[bot]: ## Unit Test Results
    2 files  ±0      2 suites  ±0   11m 6s [:stopwatch:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "duration of all tests") - 4m 5s
267 tests +1  264 [:heavy_check_mark:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "passed tests") ±0  2 [:zzz:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "skipped / disabled tests") ±0  1 [:x:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "failed tests") +1 
534 runs  +2  529 [:heavy_check_mark:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "passed tests") +1  4 [:zzz:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "skipped / disabled tests") ±0  1 [:x:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v1.20/README.md#the-symbols "failed tests") +1 

For more details on these failures, see [this check](https://github.com/CS-SI/eodag/runs/7433554006).

Results for commit 3f35bd10. ± Comparison against base commit fc01129a.

[test-results]:data:application/gzip;base64,H4sIAEQr2GIC/02Myw7CIBQFf6Vh7QLKy/ozBi+QENtieKyM/+6VttjlzDmZN/FhdpnchvEykFxD6WBrMiXEFVEphQKn0kalD7rnCtCU+KtneO2JTXgTZhSsC5dSTGgomlTXX1NyscORlOPUzVbsj1Ow8bkHcVlCQSDcc/mwjKqr8UJzLhibADRIo6xxnEmqJVjhyOcLpSwEZQUBAAA=


Patch:
diff --git a/eodag/api/core.py b/eodag/api/core.py
index 498aea3e..ffe01d83 100644
--- a/eodag/api/core.py
+++ b/eodag/api/core.py
@@ -55,6 +55,7 @@ from eodag.utils import (
     uri_to_path,
 )
 from eodag.utils.exceptions import (
+    AuthenticationError,
     NoMatchingProductType,
     PluginImplementationError,
     UnsupportedProvider,
@@ -640,6 +641,10 @@ class EODataAccessGateway(object):
                     )
                     if callable(getattr(auth_plugin, "authenticate", None)):
                         search_plugin.auth = auth_plugin.authenticate()
+                    else:
+                        raise AuthenticationError(
+                            f"Could not authenticate using {auth_plugin} plugin"
+                        )
 
                 ext_product_types_conf[
                     provider
diff --git a/eodag/plugins/search/qssearch.py b/eodag/plugins/search/qssearch.py
index d18b0630..c06a7c56 100644
--- a/eodag/plugins/search/qssearch.py
+++ b/eodag/plugins/search/qssearch.py
@@ -858,7 +858,7 @@ class QueryStringSearch(Search):
             else:
                 if info_message:
                     logger.info(info_message)
-                response = requests.get(url)
+                response = requests.get(url, **kwargs)
                 response.raise_for_status()
         except (requests.RequestException, urllib_HTTPError) as err:
             err_msg = err.readlines() if hasattr(err, "readlines") else ""


Test patch:
diff --git a/tests/context.py b/tests/context.py
index 790d8cdf..52328d1d 100644
--- a/tests/context.py
+++ b/tests/context.py
@@ -42,6 +42,7 @@ from eodag.config import (
 )
 from eodag.plugins.apis.ecmwf import EcmwfApi
 from eodag.plugins.authentication.base import Authentication
+from eodag.plugins.authentication.header import HeaderAuth
 from eodag.plugins.crunch.filter_date import FilterDate
 from eodag.plugins.crunch.filter_latest_tpl_name import FilterLatestByName
 from eodag.plugins.crunch.filter_property import FilterProperty
diff --git a/tests/integration/test_core_config.py b/tests/integration/test_core_config.py
index d54c8a22..b8cb592e 100644
--- a/tests/integration/test_core_config.py
+++ b/tests/integration/test_core_config.py
@@ -19,7 +19,13 @@
 import tempfile
 from unittest import TestCase, mock
 
-from tests.context import EODataAccessGateway, PluginConfig
+from tests.context import (
+    AuthenticationError,
+    EODataAccessGateway,
+    HeaderAuth,
+    MisconfiguredError,
+    PluginConfig,
+)
 
 
 class TestCoreProvidersConfig(TestCase):
@@ -108,3 +114,79 @@ class TestCoreProvidersConfig(TestCase):
         self.assertEqual(
             self.dag.providers_config["foo_provider"].auth.type, "GenericAuth"
         )
+
+
+class TestCoreProductTypesConfig(TestCase):
+    def setUp(self):
+        super(TestCoreProductTypesConfig, self).setUp()
+        # Mock home and eodag conf directory to tmp dir
+        self.tmp_home_dir = tempfile.TemporaryDirectory()
+        self.expanduser_mock = mock.patch(
+            "os.path.expanduser", autospec=True, return_value=self.tmp_home_dir.name
+        )
+        self.expanduser_mock.start()
+        self.dag = EODataAccessGateway()
+
+    def tearDown(self):
+        super(TestCoreProductTypesConfig, self).tearDown()
+        # stop Mock and remove tmp config dir
+        self.expanduser_mock.stop()
+        self.tmp_home_dir.cleanup()
+
+    @mock.patch("eodag.plugins.search.qssearch.requests.get", autospec=True)
+    def test_core_discover_product_types_auth(self, mock_requests_get):
+        # without auth plugin
+        self.dag.update_providers_config(
+            """
+            foo_provider:
+                search:
+                    type: StacSearch
+                    api_endpoint: https://foo.bar/search
+                    discover_product_types:
+                        fetch_url: https://foo.bar/collections
+                    need_auth: true
+                products:
+                    GENERIC_PRODUCT_TYPE:
+                        productType: '{productType}'
+            """
+        )
+        self.assertRaises(
+            AuthenticationError,
+            self.dag.discover_product_types,
+            provider="foo_provider",
+        )
+
+        # with auth plugin but without credentials
+        self.dag.update_providers_config(
+            """
+            foo_provider:
+                auth:
+                    type: HTTPHeaderAuth
+                    headers:
+                        Authorization: "Apikey {apikey}"
+            """
+        )
+        with self.assertRaisesRegex(
+            MisconfiguredError, r"Missing credentials configuration .*"
+        ):
+            self.dag.discover_product_types(provider="foo_provider")
+
+        # with auth plugin and credentials
+        self.dag.update_providers_config(
+            """
+            foo_provider:
+                auth:
+                    credentials:
+                        apikey: my-api-key
+            """
+        )
+        self.dag.discover_product_types(provider="foo_provider")
+
+        mock_requests_get.assert_called_once_with(
+            self.dag.providers_config["foo_provider"].search.discover_product_types[
+                "fetch_url"
+            ],
+            auth=mock.ANY,
+        )
+        call_args, call_kwargs = mock_requests_get.call_args
+        self.assertIsInstance(call_kwargs["auth"], HeaderAuth)