33from datetime import datetime , timedelta
44from unittest .mock import patch
55
6+ from marqo import version
67from marqo .core .exceptions import IndexNotFoundError , InternalError , UnsupportedFeatureError
78from marqo .core .models .add_docs_params import AddDocsParams
89from marqo .core .models .marqo_index import FieldType
@@ -41,12 +42,16 @@ def setUpClass(cls) -> None:
4142 # Bootstrap Vespa
4243 cls .index_management .bootstrap_vespa ()
4344
45+ cls .original_marqo_version = '2.23.0'
46+ cls .original_schema_template_version = '2.24.0'
47+
4448 # pre-create all indexes for tests
4549 index_requests = [
46- cls .unstructured_marqo_index_request (name = 'test_schema_update_index' ),
47- cls .unstructured_marqo_index_request (name = 'test_config_change_restart' ),
48- cls .unstructured_marqo_index_request (name = 'test_config_change_reindex' ),
49- cls .unstructured_marqo_index_request (name = 'test_config_change_refeed' ),
50+ cls .unstructured_marqo_index_request (name = 'test_schema_update_index' , marqo_version = cls .original_marqo_version , schema_template_version = cls .original_schema_template_version ),
51+ cls .unstructured_marqo_index_request (name = 'test_config_change_restart' , marqo_version = cls .original_marqo_version , schema_template_version = cls .original_schema_template_version ),
52+ cls .unstructured_marqo_index_request (name = 'test_config_change_reindex' , marqo_version = cls .original_marqo_version , schema_template_version = cls .original_schema_template_version ),
53+ cls .unstructured_marqo_index_request (name = 'test_config_change_refeed' , marqo_version = cls .original_marqo_version , schema_template_version = cls .original_schema_template_version ),
54+ cls .unstructured_marqo_index_request (name = 'test_schema_template_version_current' ),
5055 cls .unstructured_marqo_index_request (name = 'old_version_index' , marqo_version = '2.22.0' ),
5156 cls .unstructured_marqo_index_request (name = 'legacy_unstructured_index' , marqo_version = '2.12.0' ),
5257 cls .structured_marqo_index_request (
@@ -57,12 +62,13 @@ def setUpClass(cls) -> None:
5762 ]
5863 cls .create_indexes (index_requests )
5964
60- # feed in a doc to add a 'title' lexical field to 'test_config_change_restart'
61- cls .add_documents (cls .config , AddDocsParams (
62- index_name = 'test_config_change_restart' ,
63- docs = [{'_id' : '1' , 'title' : 'hello' }],
64- tensor_fields = []
65- ))
65+ # feed in a doc to add a 'title' lexical field to 'test_config_change_restart', keep the schema version unchanged
66+ with patch ('marqo.version.get_version' , return_value = cls .original_schema_template_version ):
67+ cls .add_documents (cls .config , AddDocsParams (
68+ index_name = 'test_config_change_restart' ,
69+ docs = [{'_id' : '1' , 'title' : 'hello' }],
70+ tensor_fields = []
71+ ))
6672
6773 def _get_validation_overrides (self ) -> str :
6874 app = self .vespa_client .download_application ()
@@ -96,7 +102,10 @@ def test_update_schema_no_changes(self):
96102 self .assertEqual (original_schema , result ['oldSchema' ])
97103 self .assertEqual (original_schema , result ['newSchema' ])
98104
99- self .assertEqual (original_version , self .index_management .get_index (test_index_name ).version )
105+ # Verify version and schema_template_version not updated (remains None when no changes)
106+ updated_index = self .index_management .get_index (test_index_name )
107+ self .assertEqual (self .original_schema_template_version , updated_index .schema_template_version )
108+ self .assertEqual (original_version , updated_index .version )
100109
101110 @patch ('marqo.core.semi_structured_vespa_index.semi_structured_vespa_schema.SemiStructuredVespaSchema.generate_vespa_schema' )
102111 def test_update_schema_successful (self , mock_generate_schema ):
@@ -126,8 +135,11 @@ def test_update_schema_successful(self, mock_generate_schema):
126135
127136 # Verify schema was actually deployed to Vespa
128137 self .assertEqual (modified_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
129- # Verify the index version is also updated
130- self .assertEqual (original_version + 1 , self .index_management .get_index (test_index_name ).version )
138+
139+ # Verify schema_template_version updated to current version; and index version becomes +1
140+ updated_index = self .index_management .get_index (test_index_name )
141+ self .assertEqual (version .get_version (), updated_index .schema_template_version )
142+ self .assertEqual (original_version + 1 , updated_index .version )
131143
132144 @patch ('marqo.core.semi_structured_vespa_index.semi_structured_vespa_schema.SemiStructuredVespaSchema.generate_vespa_schema' )
133145 def test_update_schema_dry_run_prevents_deployment (self , mock_generate_schema ):
@@ -157,6 +169,10 @@ def test_update_schema_dry_run_prevents_deployment(self, mock_generate_schema):
157169 # Verify schema was NOT deployed to Vespa (original schema still present)
158170 self .assertEqual (original_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
159171
172+ # Verify schema_template_version not updated in dry run
173+ updated_index = self .index_management .get_index (test_index_name )
174+ self .assertEqual (self .original_schema_template_version , updated_index .schema_template_version )
175+
160176 # ============================================================================
161177 # Error Case Tests
162178 # ============================================================================
@@ -182,7 +198,7 @@ def test_update_schema_wrong_index_type_legacy_unstructured(self):
182198
183199 self .assertIn ('only semi-structured indexes support schema updates' , str (ctx .exception ))
184200
185- def test_update_schema_version_too_old (self ):
201+ def test_update_schema_template_version_too_old (self ):
186202 """Should raise UnsupportedFeatureError for indexes created with Marqo < 2.23.0."""
187203 with self .assertRaisesStrict (UnsupportedFeatureError ) as ctx :
188204 self .index_management .apply_latest_schema_template ('old_version_index' )
@@ -191,6 +207,22 @@ def test_update_schema_version_too_old(self):
191207 str (ctx .exception ))
192208 self .assertIn ('created with Marqo 2.22.0' , str (ctx .exception ))
193209
210+ def test_shortcut_when_schema_template_version_current (self ):
211+ """When schema_template_version matches current version, shortcut is triggered."""
212+ current_version = version .get_version ()
213+ index_name = 'test_schema_template_version_current'
214+
215+ result = self .index_management .apply_latest_schema_template (index_name )
216+
217+ # Verify shortcut response
218+ self .assertFalse (result ['updated' ])
219+ self .assertFalse (result ['schemaChanged' ])
220+ self .assertIn (f'already at current Marqo version { current_version } ' , result ['reason' ])
221+
222+ # Verify schema_template_version unchanged
223+ index = self .index_management .get_index (index_name )
224+ self .assertEqual (current_version , index .schema_template_version )
225+
194226 # ============================================================================
195227 # configChangeActions Tests
196228 # ============================================================================
@@ -244,6 +276,10 @@ def test_update_schema_with_restart_actions(self, mock_generate_schema):
244276 # Verify schema was NOT deployed
245277 self .assertEqual (original_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
246278
279+ # Verify schema_template_version not updated when blocked
280+ blocked_index = self .index_management .get_index (test_index_name )
281+ self .assertEqual (self .original_schema_template_version , blocked_index .schema_template_version )
282+
247283 # Verify it updates the schema when forced set to true
248284 result_forced = self .index_management .apply_latest_schema_template (
249285 test_index_name ,
@@ -254,6 +290,10 @@ def test_update_schema_with_restart_actions(self, mock_generate_schema):
254290 self .assertIn ('Update forced despite required actions' , result_forced ['reason' ])
255291 self .assertEqual (modified_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
256292
293+ # Verify schema_template_version updated when forced
294+ forced_index = self .index_management .get_index (test_index_name )
295+ self .assertEqual (version .get_version (), forced_index .schema_template_version )
296+
257297 @patch ('marqo.core.semi_structured_vespa_index.semi_structured_vespa_schema.SemiStructuredVespaSchema.generate_vespa_schema' )
258298 def test_update_schema_with_refeed_actions (self , mock_generate_schema ):
259299 """When re-feed actions are required and force=False, should block deployment.
@@ -296,6 +336,10 @@ def test_update_schema_with_refeed_actions(self, mock_generate_schema):
296336
297337 self .assertEqual (original_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
298338
339+ # Verify schema_template_version not updated when blocked
340+ blocked_index = self .index_management .get_index (test_index_name )
341+ self .assertEqual (self .original_schema_template_version , blocked_index .schema_template_version )
342+
299343 # Force update
300344 result_forced = self .index_management .apply_latest_schema_template (
301345 test_index_name ,
@@ -309,6 +353,10 @@ def test_update_schema_with_refeed_actions(self, mock_generate_schema):
309353
310354 self .assertEqual (modified_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
311355
356+ # Verify schema_template_version updated when forced
357+ forced_index = self .index_management .get_index (test_index_name )
358+ self .assertEqual (version .get_version (), forced_index .schema_template_version )
359+
312360 @patch ('marqo.core.semi_structured_vespa_index.semi_structured_vespa_schema.SemiStructuredVespaSchema.generate_vespa_schema' )
313361 def test_update_schema_with_reindex_actions (self , mock_generate_schema ):
314362 """When reindex actions are required and force=False, should block deployment.
@@ -357,6 +405,10 @@ def test_update_schema_with_reindex_actions(self, mock_generate_schema):
357405
358406 self .assertEqual (original_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
359407
408+ # Verify schema_template_version not updated when blocked
409+ blocked_index = self .index_management .get_index (test_index_name )
410+ self .assertEqual (self .original_schema_template_version , blocked_index .schema_template_version )
411+
360412 # Force update
361413 result_forced = self .index_management .apply_latest_schema_template (
362414 test_index_name ,
@@ -369,3 +421,7 @@ def test_update_schema_with_reindex_actions(self, mock_generate_schema):
369421 self .assertIn ('Update forced despite required actions' , result_forced ['reason' ])
370422 self .assertIn ('reindex' , result_forced ['configChangeActions' ])
371423 self .assertEqual (modified_schema , self ._get_schema_from_vespa (saved_index .schema_name ))
424+
425+ # Verify schema_template_version updated when forced
426+ forced_index = self .index_management .get_index (test_index_name )
427+ self .assertEqual (version .get_version (), forced_index .schema_template_version )
0 commit comments