jason810496 commented on code in PR #76453:
URL: https://github.com/apache/airflow/pull/76453#discussion_r4512689948


##########
airflow-core/src/airflow/api_fastapi/core_api/routes/public/connections.py:
##########
@@ -389,16 +390,34 @@ def test_connection(
                 existing_conn = None
 
         if existing_conn is not None:
-            # Stored credentials are only reused to test the connection's own
-            # host/port; testing a different destination must supply its own.
+            # Stored credentials are only reused to test the stored connection 
itself;
+            # testing a different one must supply its own. Besides host and 
port, the
+            # connection type, schema, login and extra also decide where and 
how a hook
+            # connects (e.g. a URL in schema, or proxies and endpoints in 
extra).
             fields_set = test_body.model_fields_set
             host_changed = "host" in fields_set and not 
_same_endpoint(test_body.host, existing_conn.host)
             port_changed = "port" in fields_set and not 
_same_endpoint(test_body.port, existing_conn.port)
-            if host_changed or port_changed:
+            conn_type_changed = test_body.conn_type != existing_conn.conn_type
+            schema_changed = "schema_" in fields_set and not _same_endpoint(
+                test_body.schema_, existing_conn.schema
+            )
+            login_changed = "login" in fields_set and not 
_same_endpoint(test_body.login, existing_conn.login)
+            # Compare with the stored extra as the API shows it, with its 
secrets masked.
+            extra_changed = "extra" in fields_set and 
json.loads(test_body.extra or "{}") != json.loads(
+                ConnectionResponse.model_validate(existing_conn).extra or "{}"
+            )
+            if (
+                host_changed
+                or port_changed
+                or conn_type_changed
+                or schema_changed
+                or login_changed
+                or extra_changed
+            ):

Review Comment:
   Could we compare one normalized view of both sides instead of six per-field 
checks? Comparing the two dicts gives what a hash would, and a new field is one 
more entry in the set.
   
   ```suggestion
               fields_set = test_body.model_fields_set
               compared = {"conn_type"} | ({"host", "port", "schema_", "login", 
"extra"} & fields_set)
               # Compare with the stored connection as the API shows it, with 
its secrets masked.
               stored = ConnectionResponse.model_validate(existing_conn)
               if _connection_target(test_body, compared) != 
_connection_target(stored, compared):
   ```
   
   with this helper in place of `_same_endpoint`:
   
   ```python
   def _connection_target(conn: ConnectionBody | ConnectionResponse, fields: 
set[str]) -> dict[str, Any]:
       """Return the fields that decide where and how a hook connects, with 
blank values as None."""
       target = {name: None if (value := getattr(conn, name)) in (None, "", 0) 
else value for name in fields}
       if "extra" in target:
           target["extra"] = json.loads(conn.extra or "{}")
       return target
   ```



##########
airflow-core/src/airflow/api_fastapi/core_api/routes/public/connections.py:
##########
@@ -389,16 +390,34 @@ def test_connection(
                 existing_conn = None
 
         if existing_conn is not None:
-            # Stored credentials are only reused to test the connection's own
-            # host/port; testing a different destination must supply its own.
+            # Stored credentials are only reused to test the stored connection 
itself;
+            # testing a different one must supply its own. Besides host and 
port, the
+            # connection type, schema, login and extra also decide where and 
how a hook
+            # connects (e.g. a URL in schema, or proxies and endpoints in 
extra).
             fields_set = test_body.model_fields_set
             host_changed = "host" in fields_set and not 
_same_endpoint(test_body.host, existing_conn.host)
             port_changed = "port" in fields_set and not 
_same_endpoint(test_body.port, existing_conn.port)
-            if host_changed or port_changed:
+            conn_type_changed = test_body.conn_type != existing_conn.conn_type
+            schema_changed = "schema_" in fields_set and not _same_endpoint(
+                test_body.schema_, existing_conn.schema
+            )
+            login_changed = "login" in fields_set and not 
_same_endpoint(test_body.login, existing_conn.login)
+            # Compare with the stored extra as the API shows it, with its 
secrets masked.
+            extra_changed = "extra" in fields_set and 
json.loads(test_body.extra or "{}") != json.loads(
+                ConnectionResponse.model_validate(existing_conn).extra or "{}"
+            )

Review Comment:
   `ConnectionResponse` also masks values registered in this process's secrets 
masker, so the worker that listed the connection and the one testing it can 
mask `extra` differently. An unchanged connection from the UI then counts as 
changed and gets the 400. Could both sides go through the same masking here 
before comparing?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to