1313# limitations under the License.
1414
1515
16+ from unittest .mock import MagicMock , patch
17+
1618import pytest
1719import requests
1820from datacommons_client .models .observation import Observation
1921from datacommons_mcp .data_models .observations import DateRange
2022from datacommons_mcp .exceptions import APIKeyValidationError , InvalidAPIKeyError
2123from datacommons_mcp .utils import (
2224 VALIDATION_API_PATH ,
25+ _get_gcs_client ,
2326 filter_by_date ,
2427 read_external_content ,
2528 read_package_content ,
@@ -85,6 +88,22 @@ def test_validate_api_key_network_error(self, requests_mock):
8588
8689
8790class TestReadContent :
91+ @pytest .fixture
92+ def mock_gcs (self ):
93+ with (
94+ patch ("google.cloud.storage.Client" ) as mock_client_class ,
95+ patch ("google.cloud.storage.Blob.from_string" ) as mock_from_string ,
96+ ):
97+ _get_gcs_client .cache_clear ()
98+ mock_client = MagicMock ()
99+ mock_client_class .return_value = mock_client
100+
101+ mock_blob = MagicMock ()
102+ mock_from_string .return_value = mock_blob
103+ mock_blob .download_as_text .return_value = "gcs content"
104+
105+ yield mock_client , mock_from_string , mock_blob
106+
88107 def test_read_external_content_success (self , tmp_path , create_test_file ):
89108 create_test_file ("test.md" , "content" )
90109 assert read_external_content (str (tmp_path ), "test.md" ) == "content"
@@ -97,6 +116,52 @@ def test_read_external_content_subdir(self, tmp_path, create_test_file):
97116 def test_read_external_content_missing (self , tmp_path ):
98117 assert read_external_content (str (tmp_path ), "missing.md" ) is None
99118
119+ def test_read_external_content_gcs_success (self , mock_gcs ):
120+ mock_client , mock_from_string , mock_blob = mock_gcs
121+ mock_blob .download_as_text .return_value = "custom content 1"
122+
123+ content = read_external_content ("gs://my-bucket/path" , "test.md" )
124+
125+ assert content == "custom content 1"
126+ mock_from_string .assert_called_once_with (
127+ "gs://my-bucket/path/test.md" , client = mock_client
128+ )
129+
130+ def test_read_external_content_gcs_success_no_prefix (self , mock_gcs ):
131+ mock_client , mock_from_string , mock_blob = mock_gcs
132+ mock_blob .download_as_text .return_value = "custom content 2"
133+
134+ content = read_external_content ("gs://my-bucket" , "test.md" )
135+
136+ assert content == "custom content 2"
137+ mock_from_string .assert_called_once_with (
138+ "gs://my-bucket/test.md" , client = mock_client
139+ )
140+
141+ def test_read_external_content_gcs_not_found (self , mock_gcs ):
142+ from google .cloud .exceptions import NotFound
143+
144+ mock_client , mock_from_string , mock_blob = mock_gcs
145+ mock_blob .download_as_text .side_effect = NotFound ("Blob not found" )
146+
147+ content = read_external_content ("gs://my-bucket" , "test.md" )
148+
149+ assert content is None
150+ mock_from_string .assert_called_once_with (
151+ "gs://my-bucket/test.md" , client = mock_client
152+ )
153+
154+ def test_read_external_content_gcs_failure (self , mock_gcs ):
155+ mock_client , mock_from_string , mock_blob = mock_gcs
156+ mock_blob .download_as_text .side_effect = Exception ("GCS error" )
157+
158+ content = read_external_content ("gs://my-bucket" , "test.md" )
159+
160+ assert content is None
161+ mock_from_string .assert_called_once_with (
162+ "gs://my-bucket/test.md" , client = mock_client
163+ )
164+
100165 def test_read_package_content_success (self ):
101166 # Read actual content from the package
102167 content = read_package_content ("datacommons_mcp.instructions" , "server.md" )
0 commit comments