@@ -259,3 +259,149 @@ def test_delete_leaderboard_force(self, test_client, mock_backend):
259259 assert response .status_code == 200
260260 assert response .json ()["force" ] is True
261261 mock_backend .db .delete_leaderboard .assert_called_once_with ("test-leaderboard" , force = True )
262+
263+
264+ class TestAdminUpdateProblems :
265+ """Test admin update-problems endpoint."""
266+
267+ def test_update_problems_requires_auth (self , test_client ):
268+ """POST /admin/update-problems requires authorization."""
269+ response = test_client .post ("/admin/update-problems" , json = {})
270+ assert response .status_code == 401
271+
272+ def test_update_problems_success (self , test_client , mock_backend ):
273+ """POST /admin/update-problems returns sync results."""
274+ mock_backend .db .__enter__ = MagicMock (return_value = mock_backend .db )
275+ mock_backend .db .__exit__ = MagicMock (return_value = None )
276+
277+ mock_result = MagicMock ()
278+ mock_result .created = ["problem1" , "problem2" ]
279+ mock_result .updated = ["problem3" ]
280+ mock_result .skipped = [{"name" : "problem4" , "reason" : "no changes" }]
281+ mock_result .errors = []
282+
283+ with patch ('kernelbot.api.main.sync_problems' , return_value = mock_result ) as mock_sync :
284+ response = test_client .post (
285+ "/admin/update-problems" ,
286+ headers = {"Authorization" : "Bearer test_token" },
287+ json = {}
288+ )
289+ assert response .status_code == 200
290+ data = response .json ()
291+ assert data ["status" ] == "ok"
292+ assert data ["created" ] == ["problem1" , "problem2" ]
293+ assert data ["updated" ] == ["problem3" ]
294+ assert data ["skipped" ] == [{"name" : "problem4" , "reason" : "no changes" }]
295+ assert data ["errors" ] == []
296+
297+ # Verify default parameters
298+ mock_sync .assert_called_once ()
299+ call_kwargs = mock_sync .call_args [1 ]
300+ assert call_kwargs ["repository" ] == "gpu-mode/reference-kernels"
301+ assert call_kwargs ["branch" ] == "main"
302+ assert call_kwargs ["force" ] is False
303+ assert call_kwargs ["problem_set" ] is None
304+
305+ def test_update_problems_with_problem_set (self , test_client , mock_backend ):
306+ """POST /admin/update-problems with specific problem_set."""
307+ mock_backend .db .__enter__ = MagicMock (return_value = mock_backend .db )
308+ mock_backend .db .__exit__ = MagicMock (return_value = None )
309+
310+ mock_result = MagicMock ()
311+ mock_result .created = ["nvidia-problem" ]
312+ mock_result .updated = []
313+ mock_result .skipped = []
314+ mock_result .errors = []
315+
316+ with patch ('kernelbot.api.main.sync_problems' , return_value = mock_result ) as mock_sync :
317+ response = test_client .post (
318+ "/admin/update-problems" ,
319+ headers = {"Authorization" : "Bearer test_token" },
320+ json = {"problem_set" : "nvidia" }
321+ )
322+ assert response .status_code == 200
323+ call_kwargs = mock_sync .call_args [1 ]
324+ assert call_kwargs ["problem_set" ] == "nvidia"
325+
326+ def test_update_problems_with_force (self , test_client , mock_backend ):
327+ """POST /admin/update-problems with force=True."""
328+ mock_backend .db .__enter__ = MagicMock (return_value = mock_backend .db )
329+ mock_backend .db .__exit__ = MagicMock (return_value = None )
330+
331+ mock_result = MagicMock ()
332+ mock_result .created = []
333+ mock_result .updated = ["updated-problem" ]
334+ mock_result .skipped = []
335+ mock_result .errors = []
336+
337+ with patch ('kernelbot.api.main.sync_problems' , return_value = mock_result ) as mock_sync :
338+ response = test_client .post (
339+ "/admin/update-problems" ,
340+ headers = {"Authorization" : "Bearer test_token" },
341+ json = {"force" : True }
342+ )
343+ assert response .status_code == 200
344+ call_kwargs = mock_sync .call_args [1 ]
345+ assert call_kwargs ["force" ] is True
346+
347+ def test_update_problems_with_custom_repo_and_branch (self , test_client , mock_backend ):
348+ """POST /admin/update-problems with custom repository and branch."""
349+ mock_backend .db .__enter__ = MagicMock (return_value = mock_backend .db )
350+ mock_backend .db .__exit__ = MagicMock (return_value = None )
351+
352+ mock_result = MagicMock ()
353+ mock_result .created = []
354+ mock_result .updated = []
355+ mock_result .skipped = []
356+ mock_result .errors = []
357+
358+ with patch ('kernelbot.api.main.sync_problems' , return_value = mock_result ) as mock_sync :
359+ response = test_client .post (
360+ "/admin/update-problems" ,
361+ headers = {"Authorization" : "Bearer test_token" },
362+ json = {
363+ "repository" : "other-org/other-repo" ,
364+ "branch" : "develop"
365+ }
366+ )
367+ assert response .status_code == 200
368+ call_kwargs = mock_sync .call_args [1 ]
369+ assert call_kwargs ["repository" ] == "other-org/other-repo"
370+ assert call_kwargs ["branch" ] == "develop"
371+
372+ def test_update_problems_value_error (self , test_client , mock_backend ):
373+ """POST /admin/update-problems returns 400 on ValueError."""
374+ mock_backend .db .__enter__ = MagicMock (return_value = mock_backend .db )
375+ mock_backend .db .__exit__ = MagicMock (return_value = None )
376+
377+ with patch ('kernelbot.api.main.sync_problems' , side_effect = ValueError ("Invalid branch name" )):
378+ response = test_client .post (
379+ "/admin/update-problems" ,
380+ headers = {"Authorization" : "Bearer test_token" },
381+ json = {"branch" : "invalid/branch" }
382+ )
383+ assert response .status_code == 400
384+ assert "Invalid branch name" in response .json ()["detail" ]
385+
386+ def test_update_problems_with_errors (self , test_client , mock_backend ):
387+ """POST /admin/update-problems includes errors in response."""
388+ mock_backend .db .__enter__ = MagicMock (return_value = mock_backend .db )
389+ mock_backend .db .__exit__ = MagicMock (return_value = None )
390+
391+ mock_result = MagicMock ()
392+ mock_result .created = []
393+ mock_result .updated = []
394+ mock_result .skipped = []
395+ mock_result .errors = [{"name" : "bad-problem" , "error" : "create failed: DB error" }]
396+
397+ with patch ('kernelbot.api.main.sync_problems' , return_value = mock_result ):
398+ response = test_client .post (
399+ "/admin/update-problems" ,
400+ headers = {"Authorization" : "Bearer test_token" },
401+ json = {}
402+ )
403+ assert response .status_code == 200
404+ data = response .json ()
405+ assert data ["status" ] == "ok"
406+ assert len (data ["errors" ]) == 1
407+ assert data ["errors" ][0 ]["name" ] == "bad-problem"
0 commit comments