@@ -883,8 +883,72 @@ def test_parse_graphql_response_non_dict_error(self):
883883 assert str (excinfo .value ) == "Response payload is not a valid JSON dictionary."
884884
885885
886+ class TestImpersonation :
887+ """Unit tests for Impersonation class and constructor validation."""
888+
889+ def test_unauthenticated_factory (self ):
890+ """Tests factory method for unauthenticated impersonation."""
891+ imp = dataconnect .Impersonation .unauthenticated ()
892+ assert imp == {"unauthenticated" : True }
893+
894+ def test_authenticated_factory (self ):
895+ """Tests factory method for authenticated impersonation."""
896+ claims = {"sub" : "user_123" }
897+ imp = dataconnect .Impersonation .authenticated (claims )
898+ assert imp == {"authClaims" : {"sub" : "user_123" }}
899+
900+ def test_constructor_unauthenticated (self ):
901+ """Tests direct constructor with unauthenticated=True."""
902+ imp = dataconnect .Impersonation (unauthenticated = True )
903+ assert imp == {"unauthenticated" : True }
904+
905+ def test_constructor_auth_claims (self ):
906+ """Tests direct constructor with auth_claims dict."""
907+ claims = {"sub" : "user_123" }
908+ imp = dataconnect .Impersonation (auth_claims = claims )
909+ assert imp == {"authClaims" : {"sub" : "user_123" }}
910+
911+ def test_constructor_auth_claims_camel_case (self ):
912+ """Tests direct constructor with authClaims dict."""
913+ claims = {"sub" : "user_123" }
914+ imp = dataconnect .Impersonation (authClaims = claims )
915+ assert imp == {"authClaims" : {"sub" : "user_123" }}
916+
917+ def test_constructor_both_claims_and_camel_case_fails (self ):
918+ """Tests specifying both auth_claims and authClaims raises ValueError."""
919+ with pytest .raises (ValueError , match = "Cannot specify both 'auth_claims' and 'authClaims'." ):
920+ dataconnect .Impersonation (auth_claims = {"sub" : "1" }, authClaims = {"sub" : "2" })
921+
922+ def test_constructor_neither_unauth_nor_claims_fails (self ):
923+ """Tests specifying neither unauthenticated nor claims raises ValueError."""
924+ with pytest .raises (
925+ ValueError ,
926+ match = "Impersonation requires either 'unauthenticated=True' or 'auth_claims'."
927+ ):
928+ dataconnect .Impersonation ()
929+
930+ def test_constructor_both_unauth_and_claims_fails (self ):
931+ """Tests specifying both unauthenticated and claims raises ValueError."""
932+ with pytest .raises (
933+ ValueError ,
934+ match = "Cannot specify both 'unauthenticated' and 'auth_claims'."
935+ ):
936+ dataconnect .Impersonation (unauthenticated = True , auth_claims = {"sub" : "123" })
937+
938+ def test_constructor_invalid_unauthenticated_type (self ):
939+ """Tests non-boolean unauthenticated raises ValueError."""
940+ with pytest .raises (ValueError , match = "'unauthenticated' must be a boolean." ):
941+ dataconnect .Impersonation (unauthenticated = "not-a-bool" )
942+
943+ def test_constructor_invalid_auth_claims_type (self ):
944+ """Tests non-dict auth_claims raises ValueError."""
945+ with pytest .raises (ValueError , match = "'auth_claims' must be a dictionary." ):
946+ dataconnect .Impersonation (auth_claims = "not-a-dict" )
947+
948+
886949class TestDataConnectExecuteGraphql :
887950
951+
888952 def setup_method (self ):
889953 self .cred = testutils .MockCredential ()
890954 self .app = firebase_admin .initialize_app (
@@ -990,9 +1054,10 @@ class User:
9901054 name : str
9911055
9921056 options = dataconnect .GraphqlOptions (variables = {"name" : "Fred" })
993- with pytest .raises (ValueError , match = "Expected variables of type User" ):
1057+ with pytest .raises (ValueError , match = "variables must be of type User" ):
9941058 self .api_client .execute_graphql ("query { foo }" , options = options , variables_type = User )
9951059
1060+
9961061 @mock .patch .object (dataconnect ._DataConnectApiClient , "_make_gql_request" )
9971062
9981063 def test_execute_graphql_success (self , mock_make_gql_request ):
0 commit comments