Skip to content

Add Or Update Networks #1097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
39 changes: 39 additions & 0 deletions meilisearch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ def multi_search(
queries:
List of dictionaries containing the specified indexes and their search queries
https://www.meilisearch.com/docs/reference/api/search#search-in-an-index
It can also include remote options in federationOptions for each query
https://www.meilisearch.com/docs/reference/api/network
federation: (optional):
Dictionary containing offset and limit
https://www.meilisearch.com/docs/reference/api/multi_search
Expand Down Expand Up @@ -756,6 +758,43 @@ def generate_tenant_token(

return jwt_token

def add_or_update_networks(self, body: Union[MutableMapping[str, Any], None]) -> Dict[str, str]:
"""Set all the Remote Networks

Parameters
----------
body:
Remote networks that are allowed

Returns
-------
remote networks:
Remote Networks containing information about the networks allowed/present.
https://www.meilisearch.com/docs/reference/api/network

Raises
------
MeilisearchApiError
An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
"""

return self.http.patch(path=f"{self.config.paths.network}", body=body)

def get_all_networks(self) -> Dict[str, str]:
"""Fetches all the remote-networks present

Returns
-------
remote networks:
All remote networks containing information about each remote and their respective remote-name and searchApi key

Raises
------
MeilisearchApiError
An error containing details about why Meilisearch can't process your request. Meilisearch error codes are described here: https://www.meilisearch.com/docs/reference/errors/error_codes#meilisearch-errors
"""
return self.http.get(path=f"{self.config.paths.network}")

@staticmethod
def _base64url_encode(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode("utf-8").replace("=", "")
Expand Down
1 change: 1 addition & 0 deletions meilisearch/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Paths:
proximity_precision = "proximity-precision"
localized_attributes = "localized-attributes"
edit = "edit"
network = "network"

def __init__(
self,
Expand Down
35 changes: 34 additions & 1 deletion tests/client/test_client_multi_search_meilisearch.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest

from meilisearch.errors import MeilisearchApiError
from tests.common import INDEX_UID
from tests.common import INDEX_UID, REMOTE_MS_1, REMOTE_MS_2


def test_basic_multi_search(client, empty_index):
Expand Down Expand Up @@ -75,3 +75,36 @@ def test_multi_search_with_federation_options(client, index_with_documents):
assert response["hits"][0]["_federation"]["weightedRankingScore"] >= 0.99
assert response["limit"] == 2
assert response["offset"] == 0


@pytest.mark.usefixtures("enable_network_options")
def test_multi_search_with_network(client, index_with_documents):
"""Tests multi-search with network, with federation options."""
index_with_documents()
resp = client.add_or_update_networks(
{
"self": REMOTE_MS_1,
"remotes": {
REMOTE_MS_1: {
"url": "http://ms-1235.example.meilisearch.io",
"searchApiKey": "xxxxxxxx",
},
REMOTE_MS_2: {
"url": "http://ms-1255.example.meilisearch.io",
"searchApiKey": "xxxxxxxx",
},
},
}
)
response = client.multi_search(
[{"indexUid": INDEX_UID, "q": "", "federationOptions": {"remote": REMOTE_MS_1}}],
federation={},
)

assert "results" not in resp
assert "results" not in response
assert isinstance(response["hits"], list)
assert len(response["hits"]) >= 0
assert response["hits"][0]["_federation"]["indexUid"] == INDEX_UID
assert response["hits"][0]["_federation"]["remote"] == REMOTE_MS_1
assert response["remoteErrors"] == {}
30 changes: 30 additions & 0 deletions tests/client/test_client_network.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import pytest

from tests.common import REMOTE_MS_1, REMOTE_MS_2


@pytest.mark.usefixtures("enable_network_options")
def test_get_all_networks(client):
"""Tests get all network in MS"""
response = client.get_all_networks()

assert isinstance(response, dict)


@pytest.mark.usefixtures("enable_network_options")
def test_add_or_update_networks(client):
"""Tests upsert network remote instance."""
body = {
"self": REMOTE_MS_1,
"remotes": {
REMOTE_MS_1: {"url": "http://localhost:7700", "searchApiKey": "xxxxxxxxxxxxxx"},
REMOTE_MS_2: {"url": "http://localhost:7720", "searchApiKey": "xxxxxxxxxxxxxxx"},
},
}
response = client.add_or_update_networks(body=body)

assert isinstance(response, dict)
assert response["self"] == REMOTE_MS_1
assert len(response["remotes"]) >= 2
assert REMOTE_MS_2 in response["remotes"]
assert REMOTE_MS_1 in response["remotes"]
Comment on lines +14 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider adding edge case tests

The happy path test looks good, but consider adding tests for edge cases such as:

  1. Empty remotes dictionary
  2. Invalid URLs or API keys
  3. Non-existent remote instances

Also, ensure that the test URLs don't point to actual production services. The current localhost URLs look good, but it's worth verifying these are test environments only.


🏁 Script executed:

#!/bin/bash
# Check if there are any other URLs used in tests
rg --ignore-case "http" tests/ | grep -v "localhost" | grep -v "127.0.0.1"

Length of output: 1884


Enhance test_add_or_update_networks with edge‐case coverage

While the happy-path for upserting networks looks solid, please add tests for these scenarios in tests/client/test_client_network.py:

  • Empty remotes dictionary (what should the response be? error vs. no-ops)
  • Malformed URLs (e.g. htp://…) or missing/invalid API keys
  • self value not included in the remotes payload
  • Non-existent remote instance identifiers

Note: this test already uses only localhost endpoints, so there’s no risk of hitting production services here.

🤖 Prompt for AI Agents
In tests/client/test_client_network.py around lines 14 to 30, the current test
only covers the happy path for adding or updating networks. To improve coverage,
add separate test cases for edge scenarios: an empty remotes dictionary to
verify behavior (error or no-op), malformed URLs or invalid/missing API keys to
check validation, a self value not present in the remotes dictionary to test
consistency, and non-existent remote instance identifiers to confirm error
handling. Ensure these tests use localhost URLs or mocks to avoid external
calls.

3 changes: 3 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
{"uid": INDEX_UID2, "options": {"primaryKey": "book_id"}},
{"uid": INDEX_UID3, "options": {"uid": "wrong", "primaryKey": "book_id"}},
]

REMOTE_MS_1 = "ms_001"
REMOTE_MS_2 = "ms_002"
17 changes: 17 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,20 @@ def new_embedders():
"default": UserProvidedEmbedder(dimensions=1).model_dump(by_alias=True),
"open_ai": OpenAiEmbedder().model_dump(by_alias=True),
}


@fixture
def enable_network_options():
requests.patch(
f"{common.BASE_URL}/experimental-features",
headers={"Authorization": f"Bearer {common.MASTER_KEY}"},
json={"network": True},
timeout=10,
)
yield
requests.patch(
f"{common.BASE_URL}/experimental-features",
headers={"Authorization": f"Bearer {common.MASTER_KEY}"},
json={"network": False},
timeout=10,
)