@@ -150,4 +150,92 @@ def run_test_manual_api(my_predbat):
150150 my_predbat .api_select ("manual_api" , "off" )
151151 my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
152152
153+ # --- api_select_update()'s storage-layer dedup rules (#4405) ---
154+ my_predbat .api_select ("manual_api" , "rates_import_override?date=2026-08-21&start=00:00:00&end=01:00:00&rate=0" )
155+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
156+ my_predbat .api_select ("manual_api" , "rates_import_override?date=2026-08-22&start=00:00:00&end=01:00:00&rate=0" )
157+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
158+ my_predbat .api_select ("manual_api" , "rates_import_override?date=2026-08-22&start=00:00:00&end=01:00:00&rate=0" )
159+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
160+ items = my_predbat .get_manual_api ("rates_import_override" )
161+ expected = [
162+ {"index" : None , "value" : {"date" : "2026-08-21" , "start" : "00:00:00" , "end" : "01:00:00" , "rate" : "0" }},
163+ {"index" : None , "value" : {"date" : "2026-08-22" , "start" : "00:00:00" , "end" : "01:00:00" , "rate" : "0" }},
164+ ]
165+ if items != expected :
166+ print ("ERROR: T17 Expecting distinct no-index entries to coexist and an exact-duplicate resend to be a no-op, got {}" .format (items ))
167+ failed = 1
168+
169+ my_predbat .api_select ("manual_api" , "off" )
170+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
171+ my_predbat .api_select ("manual_api" , "rates_import_override(0)?date=2026-08-21&start=00:00:00&end=01:00:00&rate=0" )
172+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
173+ my_predbat .api_select ("manual_api" , "rates_import_override(0)?date=2026-08-21&start=00:00:00&end=01:00:00&rate=5" )
174+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
175+ my_predbat .api_select ("manual_api" , "rates_import_override(1)?date=2026-08-22&start=00:00:00&end=01:00:00&rate=9" )
176+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
177+ items = my_predbat .get_manual_api ("rates_import_override" )
178+ expected = [
179+ {"index" : 0 , "value" : {"date" : "2026-08-21" , "start" : "00:00:00" , "end" : "01:00:00" , "rate" : "5" }},
180+ {"index" : 1 , "value" : {"date" : "2026-08-22" , "start" : "00:00:00" , "end" : "01:00:00" , "rate" : "9" }},
181+ ]
182+ if items != expected :
183+ print ("ERROR: T18 Expecting a same-index resend to replace and distinct indices to coexist, got {}" .format (items ))
184+ failed = 1
185+
186+ my_predbat .api_select ("manual_api" , "off" )
187+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
188+ my_predbat .api_select ("manual_api" , "inverter_limit=1000" )
189+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
190+ my_predbat .api_select ("manual_api" , "inverter_limit=2000" )
191+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
192+ items = my_predbat .get_manual_api ("inverter_limit" )
193+ expected = [{"index" : None , "value" : "2000" }]
194+ if items != expected :
195+ print ("ERROR: T19 Expecting a scalar (non-dict_list) no-index override to still replace on resend, got {}" .format (items ))
196+ failed = 1
197+
198+ # --- get_arg()/basic_rates() merge behaviour built on top of that storage (#4405) ---
199+ my_predbat .api_select ("manual_api" , "off" )
200+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
201+ my_predbat .args ["rates_import_override" ] = []
202+ my_predbat .api_select ("manual_api" , "rates_import_override?start=01:00:00&end=02:00:00&rate=5" )
203+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
204+ my_predbat .api_select ("manual_api" , "rates_import_override?start=03:00:00&end=04:00:00&rate=9" )
205+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
206+ info = my_predbat .get_arg ("rates_import_override" , [], indirect = False )
207+ expected = [
208+ {"start" : "01:00:00" , "end" : "02:00:00" , "rate" : "5" },
209+ {"start" : "03:00:00" , "end" : "04:00:00" , "rate" : "9" },
210+ ]
211+ if info != expected :
212+ print ("ERROR: T20 Expecting get_arg to merge both no-index dict_list overrides, got {}" .format (info ))
213+ failed = 1
214+
215+ rates = my_predbat .basic_rates (info , "rates_import_override" )
216+ if rates .get (75 ) != 5 or rates .get (195 ) != 9 :
217+ print ("ERROR: T20 Expecting minutes 75/195 to take rates 5/9 from the two windows, got {}/{}" .format (rates .get (75 ), rates .get (195 )))
218+ failed = 1
219+
220+ my_predbat .api_select ("manual_api" , "rates_import_override(0)?date=2026-08-22&start=00:00:00&end=01:00:00&rate=5" )
221+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
222+ info = my_predbat .get_arg ("rates_import_override" , [], indirect = False )
223+ if len (info ) != 3 :
224+ print ("ERROR: T21 Expecting no-index and explicit-index overrides to all survive together, got {}" .format (info ))
225+ failed = 1
226+
227+ # --- A malformed index must not crash api_select_update ---
228+ my_predbat .api_select ("manual_api" , "off" )
229+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
230+ try :
231+ my_predbat .api_select ("manual_api" , "rates_import_override(x)?date=2026-08-21&start=00:00:00&end=01:00:00&rate=0" )
232+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
233+ except ValueError as e :
234+ print ("ERROR: T22 Expecting a malformed index to not crash api_select_update, got {}" .format (e ))
235+ failed = 1
236+
237+ my_predbat .api_select ("manual_api" , "off" )
238+ my_predbat .manual_api = my_predbat .api_select_update ("manual_api" )
239+ del my_predbat .args ["rates_import_override" ]
240+
153241 return failed
0 commit comments