@@ -406,6 +406,99 @@ def test_create_inst_duplicate_name_state_ok_when_existing_row_is_valid(
406406 assert data ["edvise_id" ] is None
407407
408408
409+ def test_create_inst_rejects_is_pdp_without_pdp_id (datakinder_client : TestClient ) -> None :
410+ """is_pdp alone does not set a school type; pdp_id is required for PDP (POST parity)."""
411+ os .environ ["ENV" ] = "DEV"
412+ response = datakinder_client .post (
413+ "/institutions" ,
414+ json = {"name" : "pdp_flag_only" , "state" : "WA" , "is_pdp" : True },
415+ )
416+ assert response .status_code == 400
417+ assert "exactly one" in response .json ()["detail" ].lower ()
418+
419+
420+ def test_create_inst_rejects_duplicate_when_existing_row_has_conflicting_ids (
421+ datakinder_client : TestClient ,
422+ session : sqlalchemy .orm .Session ,
423+ ) -> None :
424+ """POST (name, state) match must 400 if stored row violates mutual exclusivity."""
425+ inst = session .get (InstTable , UUID_1 )
426+ assert inst is not None
427+ saved = (inst .pdp_id , inst .edvise_id , inst .legacy_id )
428+ try :
429+ inst .edvise_id = "corrupt_edvise"
430+ session .commit ()
431+ response = datakinder_client .post (
432+ "/institutions" ,
433+ json = {
434+ "name" : "school_1" ,
435+ "state" : "GA" ,
436+ "pdp_id" : "456" ,
437+ "is_pdp" : True ,
438+ },
439+ )
440+ assert response .status_code == 400
441+ assert "more than one" in response .json ()["detail" ].lower ()
442+ finally :
443+ inst .pdp_id , inst .edvise_id , inst .legacy_id = saved
444+ session .commit ()
445+
446+
447+ def test_update_inst_patch_is_edvise_on_pdp_institution_returns_400 (
448+ datakinder_client : TestClient ,
449+ ) -> None :
450+ """Cannot set is_edvise intent while row still has pdp_id (must clear in same PATCH)."""
451+ MOCK_STORAGE .create_bucket .return_value = None
452+ MOCK_STORAGE .create_folders .return_value = None
453+ MOCK_DATABRICKS .setup_new_inst .return_value = None
454+
455+ response = datakinder_client .patch (
456+ "/institutions/" + uuid_to_str (UUID_1 ),
457+ json = {"is_edvise" : True },
458+ )
459+ assert response .status_code == 400
460+ assert "more than one" in response .json ()["detail" ].lower ()
461+
462+
463+ def test_update_inst_patch_both_is_edvise_and_is_legacy_returns_400 (
464+ datakinder_client : TestClient ,
465+ ) -> None :
466+ """PATCH cannot indicate both Edvise and Legacy in one request."""
467+ MOCK_STORAGE .create_bucket .return_value = None
468+ MOCK_STORAGE .create_folders .return_value = None
469+ MOCK_DATABRICKS .setup_new_inst .return_value = None
470+
471+ response = datakinder_client .patch (
472+ "/institutions/" + uuid_to_str (UUID_2 ),
473+ json = {"is_edvise" : True , "is_legacy" : True },
474+ )
475+ assert response .status_code == 400
476+ assert "more than one" in response .json ()["detail" ].lower ()
477+
478+
479+ def test_update_inst_allowed_schemas_only_updates_schemas (
480+ datakinder_client : TestClient ,
481+ session : sqlalchemy .orm .Session ,
482+ ) -> None :
483+ """allowed_schemas without changing type triple replaces schemas (no recompute merge)."""
484+ MOCK_STORAGE .create_bucket .return_value = None
485+ MOCK_STORAGE .create_folders .return_value = None
486+ MOCK_DATABRICKS .setup_new_inst .return_value = None
487+
488+ inst = session .get (InstTable , UUID_1 )
489+ assert inst is not None
490+ inst .schemas = ["STUDENT" , "COURSE" ]
491+ session .commit ()
492+
493+ response = datakinder_client .patch (
494+ "/institutions/" + uuid_to_str (UUID_1 ),
495+ json = {"allowed_schemas" : ["UNKNOWN" ]},
496+ )
497+ assert response .status_code == 200
498+ session .refresh (inst )
499+ assert inst .schemas == ["UNKNOWN" ]
500+
501+
409502def test_edit_inst (datakinder_client : TestClient ) -> None :
410503 """Test PATCH /institutions/<uuid>. For various user access types."""
411504 MOCK_STORAGE .create_bucket .return_value = None
0 commit comments