39
39
from tests .common import MockConfigEntry
40
40
41
41
42
- @pytest .fixture
43
- def mock_models ():
44
- """Mock the model list API."""
42
+ def get_models_pager ():
43
+ """Return a generator that yields the models."""
45
44
model_20_flash = Mock (
46
45
display_name = "Gemini 2.0 Flash" ,
47
46
supported_actions = ["generateContent" ],
@@ -72,11 +71,7 @@ async def models_pager():
72
71
yield model_15_pro
73
72
yield model_10_pro
74
73
75
- with patch (
76
- "google.genai.models.AsyncModels.list" ,
77
- return_value = models_pager (),
78
- ):
79
- yield
74
+ return models_pager ()
80
75
81
76
82
77
async def test_form (hass : HomeAssistant ) -> None :
@@ -119,8 +114,13 @@ async def test_form(hass: HomeAssistant) -> None:
119
114
assert len (mock_setup_entry .mock_calls ) == 1
120
115
121
116
117
+ def will_options_be_rendered_again (current_options , new_options ) -> bool :
118
+ """Determine if options will be rendered again."""
119
+ return current_options .get (CONF_RECOMMENDED ) != new_options .get (CONF_RECOMMENDED )
120
+
121
+
122
122
@pytest .mark .parametrize (
123
- ("current_options" , "new_options" , "expected_options" ),
123
+ ("current_options" , "new_options" , "expected_options" , "errors" ),
124
124
[
125
125
(
126
126
{
@@ -147,6 +147,7 @@ async def test_form(hass: HomeAssistant) -> None:
147
147
CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
148
148
CONF_USE_GOOGLE_SEARCH_TOOL : RECOMMENDED_USE_GOOGLE_SEARCH_TOOL ,
149
149
},
150
+ None ,
150
151
),
151
152
(
152
153
{
@@ -157,6 +158,7 @@ async def test_form(hass: HomeAssistant) -> None:
157
158
CONF_TOP_P : RECOMMENDED_TOP_P ,
158
159
CONF_TOP_K : RECOMMENDED_TOP_K ,
159
160
CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
161
+ CONF_USE_GOOGLE_SEARCH_TOOL : True ,
160
162
},
161
163
{
162
164
CONF_RECOMMENDED : True ,
@@ -168,42 +170,152 @@ async def test_form(hass: HomeAssistant) -> None:
168
170
CONF_LLM_HASS_API : "assist" ,
169
171
CONF_PROMPT : "" ,
170
172
},
173
+ None ,
174
+ ),
175
+ (
176
+ {
177
+ CONF_RECOMMENDED : False ,
178
+ CONF_PROMPT : "Speak like a pirate" ,
179
+ CONF_TEMPERATURE : 0.3 ,
180
+ CONF_CHAT_MODEL : RECOMMENDED_CHAT_MODEL ,
181
+ CONF_TOP_P : RECOMMENDED_TOP_P ,
182
+ CONF_TOP_K : RECOMMENDED_TOP_K ,
183
+ CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
184
+ CONF_HARASSMENT_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
185
+ CONF_HATE_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
186
+ CONF_SEXUAL_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
187
+ CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
188
+ CONF_USE_GOOGLE_SEARCH_TOOL : RECOMMENDED_USE_GOOGLE_SEARCH_TOOL ,
189
+ },
190
+ {
191
+ CONF_RECOMMENDED : False ,
192
+ CONF_PROMPT : "Speak like a pirate" ,
193
+ CONF_TEMPERATURE : 0.3 ,
194
+ CONF_CHAT_MODEL : RECOMMENDED_CHAT_MODEL ,
195
+ CONF_TOP_P : RECOMMENDED_TOP_P ,
196
+ CONF_TOP_K : RECOMMENDED_TOP_K ,
197
+ CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
198
+ CONF_HARASSMENT_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
199
+ CONF_HATE_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
200
+ CONF_SEXUAL_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
201
+ CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
202
+ CONF_USE_GOOGLE_SEARCH_TOOL : True ,
203
+ },
204
+ {
205
+ CONF_RECOMMENDED : False ,
206
+ CONF_PROMPT : "Speak like a pirate" ,
207
+ CONF_TEMPERATURE : 0.3 ,
208
+ CONF_CHAT_MODEL : RECOMMENDED_CHAT_MODEL ,
209
+ CONF_TOP_P : RECOMMENDED_TOP_P ,
210
+ CONF_TOP_K : RECOMMENDED_TOP_K ,
211
+ CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
212
+ CONF_HARASSMENT_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
213
+ CONF_HATE_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
214
+ CONF_SEXUAL_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
215
+ CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
216
+ CONF_USE_GOOGLE_SEARCH_TOOL : True ,
217
+ },
218
+ None ,
219
+ ),
220
+ (
221
+ {
222
+ CONF_RECOMMENDED : False ,
223
+ CONF_PROMPT : "Speak like a pirate" ,
224
+ CONF_TEMPERATURE : 0.3 ,
225
+ CONF_CHAT_MODEL : RECOMMENDED_CHAT_MODEL ,
226
+ CONF_TOP_P : RECOMMENDED_TOP_P ,
227
+ CONF_TOP_K : RECOMMENDED_TOP_K ,
228
+ CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
229
+ CONF_HARASSMENT_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
230
+ CONF_HATE_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
231
+ CONF_SEXUAL_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
232
+ CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
233
+ CONF_USE_GOOGLE_SEARCH_TOOL : True ,
234
+ },
235
+ {
236
+ CONF_RECOMMENDED : False ,
237
+ CONF_PROMPT : "Speak like a pirate" ,
238
+ CONF_LLM_HASS_API : "assist" ,
239
+ CONF_TEMPERATURE : 0.3 ,
240
+ CONF_CHAT_MODEL : RECOMMENDED_CHAT_MODEL ,
241
+ CONF_TOP_P : RECOMMENDED_TOP_P ,
242
+ CONF_TOP_K : RECOMMENDED_TOP_K ,
243
+ CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
244
+ CONF_HARASSMENT_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
245
+ CONF_HATE_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
246
+ CONF_SEXUAL_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
247
+ CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
248
+ CONF_USE_GOOGLE_SEARCH_TOOL : True ,
249
+ },
250
+ {
251
+ CONF_RECOMMENDED : False ,
252
+ CONF_PROMPT : "Speak like a pirate" ,
253
+ CONF_TEMPERATURE : 0.3 ,
254
+ CONF_CHAT_MODEL : RECOMMENDED_CHAT_MODEL ,
255
+ CONF_TOP_P : RECOMMENDED_TOP_P ,
256
+ CONF_TOP_K : RECOMMENDED_TOP_K ,
257
+ CONF_MAX_TOKENS : RECOMMENDED_MAX_TOKENS ,
258
+ CONF_HARASSMENT_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
259
+ CONF_HATE_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
260
+ CONF_SEXUAL_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
261
+ CONF_DANGEROUS_BLOCK_THRESHOLD : RECOMMENDED_HARM_BLOCK_THRESHOLD ,
262
+ CONF_USE_GOOGLE_SEARCH_TOOL : True ,
263
+ },
264
+ {CONF_USE_GOOGLE_SEARCH_TOOL : "invalid_google_search_option" },
171
265
),
172
266
],
173
267
)
174
268
@pytest .mark .usefixtures ("mock_init_component" )
175
269
async def test_options_switching (
176
270
hass : HomeAssistant ,
177
271
mock_config_entry : MockConfigEntry ,
178
- mock_models ,
179
272
current_options ,
180
273
new_options ,
181
274
expected_options ,
275
+ errors ,
182
276
) -> None :
183
277
"""Test the options form."""
184
278
with patch ("google.genai.models.AsyncModels.get" ):
185
279
hass .config_entries .async_update_entry (
186
280
mock_config_entry , options = current_options
187
281
)
188
282
await hass .async_block_till_done ()
189
- options_flow = await hass .config_entries .options .async_init (
190
- mock_config_entry .entry_id
191
- )
192
- if current_options .get (CONF_RECOMMENDED ) != new_options .get (CONF_RECOMMENDED ):
193
- options_flow = await hass .config_entries .options .async_configure (
283
+ with patch (
284
+ "google.genai.models.AsyncModels.list" ,
285
+ return_value = get_models_pager (),
286
+ ):
287
+ options_flow = await hass .config_entries .options .async_init (
288
+ mock_config_entry .entry_id
289
+ )
290
+ if will_options_be_rendered_again (current_options , new_options ):
291
+ retry_options = {
292
+ ** current_options ,
293
+ CONF_RECOMMENDED : new_options [CONF_RECOMMENDED ],
294
+ }
295
+ with patch (
296
+ "google.genai.models.AsyncModels.list" ,
297
+ return_value = get_models_pager (),
298
+ ):
299
+ options_flow = await hass .config_entries .options .async_configure (
300
+ options_flow ["flow_id" ],
301
+ retry_options ,
302
+ )
303
+ with patch (
304
+ "google.genai.models.AsyncModels.list" ,
305
+ return_value = get_models_pager (),
306
+ ):
307
+ options = await hass .config_entries .options .async_configure (
194
308
options_flow ["flow_id" ],
195
- {
196
- ** current_options ,
197
- CONF_RECOMMENDED : new_options [CONF_RECOMMENDED ],
198
- },
309
+ new_options ,
199
310
)
200
- options = await hass .config_entries .options .async_configure (
201
- options_flow ["flow_id" ],
202
- new_options ,
203
- )
204
311
await hass .async_block_till_done ()
205
- assert options ["type" ] is FlowResultType .CREATE_ENTRY
206
- assert options ["data" ] == expected_options
312
+ if errors is None :
313
+ assert options ["type" ] is FlowResultType .CREATE_ENTRY
314
+ assert options ["data" ] == expected_options
315
+
316
+ else :
317
+ assert options ["type" ] is FlowResultType .FORM
318
+ assert options .get ("errors" , None ) == errors
207
319
208
320
209
321
@pytest .mark .parametrize (
0 commit comments