ashb commented on code in PR #68700:
URL: https://github.com/apache/airflow/pull/68700#discussion_r3435318971


##########
airflow-core/tests/unit/always/test_secrets_local_filesystem.py:
##########


Review Comment:
   I'm not sure this test adds anything -- the secrets backend just provides a 
str/json value to the Connection object, all the logic we are testing here 
lives inside connection.
   
   I think remove the added secret backend tests



##########
airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_connections.py:
##########
@@ -153,6 +153,17 @@ def test_get_should_respond_200(self, test_client, 
testing_team, session):
         assert body["conn_type"] == TEST_CONN_TYPE
         assert body["team_name"] == testing_team.name
 
+    def test_get_should_return_existing_connection_with_invalid_port(self, 
test_client, session):
+        session.execute(
+            Connection.__table__.insert().values(conn_id=TEST_CONN_ID, 
conn_type=TEST_CONN_TYPE, port=0)
+        )

Review Comment:
   Odd way of doing this:
   
   ```suggestion
           session.add(
               Connection(conn_id=TEST_CONN_ID, conn_type=TEST_CONN_TYPE, 
port=0)
           )
   ```
   
   is more normal for what we do in Airflow.



##########
airflow-core/tests/unit/models/test_connection.py:
##########
@@ -540,3 +593,18 @@ def test_get_conn_id_to_team_name_mapping(self, 
testing_team: Team, session: Ses
             "test_conn2": None,
         }
         clear_db_connections()
+
+    @pytest.mark.db_test
+    def test_existing_connection_with_invalid_port_can_be_loaded(self, 
session: Session):
+        clear_db_connections()
+        session.execute(
+            
Connection.__table__.insert().values(conn_id="legacy_invalid_port", 
conn_type="test", port=0)

Review Comment:
   Same here -- `session.add`.



##########
airflow-core/src/airflow/models/connection.py:
##########
@@ -219,6 +222,32 @@ def _validate_extra(extra, conn_id) -> None:
             raise ValueError(f"Encountered non-JSON in `extra` field for 
connection {conn_id!r}.")
         return None
 
+    @staticmethod
+    def _coerce_port(port: int | str | None) -> int | None:
+        if port is None:
+            return None
+        if isinstance(port, bool):
+            raise ValueError(f"Expected integer value for `port`, but got 
{port!r} instead.")
+        if isinstance(port, int):
+            return port
+        if isinstance(port, str):
+            try:
+                return int(port)
+            except ValueError:
+                raise ValueError(f"Expected integer value for `port`, but got 
{port!r} instead.") from None
+        raise ValueError(f"Expected integer value for `port`, but got {port!r} 
instead.")

Review Comment:
   Nit: Feels like a text-book example of where structual matching is suited.
   ```suggestion
           match port:
               case None:
                   return None
               case bool():
                   raise ValueError(f"Expected integer value for `port`, but 
got {port!r} instead.")
               case int():
                   return port
               case str():
                   try:
                       return int(port)
                   except ValueError:
                       raise ValueError(f"Expected integer value for `port`, 
but got {port!r} instead.") from None
               case _:
               raise ValueError(f"Expected integer value for `port`, but got 
{port!r} instead.")
   ```



##########
airflow-core/src/airflow/api_fastapi/core_api/openapi/v2-rest-api-generated.yaml:
##########
@@ -12771,6 +12771,8 @@ components:
         port:
           anyOf:
           - type: integer
+            maximum: 65535.0
+            minimum: 1.0

Review Comment:
   We have a bit of a problem here .. while this is "correct", by specifying 
this in the schema, it is likely that clients generated from it will also 
enforce this, and thus reject the invalid ports in any response they receive.
   
   If that is a problem or not is the question (as any such port would have 
been "invalid at use" anyway. Needs consideration



##########
airflow-core/tests/unit/models/test_connection.py:
##########
@@ -221,6 +223,57 @@ def test_parse_from_uri(
             assert conn.schema == expected_schema
             assert conn.extra_dejson == expected_extra_dict
 
+    @pytest.mark.parametrize(
+        ("port", "expected_port"),
+        [
+            (None, None),
+            (1, 1),
+            ("1", 1),
+            (65535, 65535),
+            ("65535", 65535),
+        ],
+    )
+    def test_connection_accepts_valid_ports(self, port, expected_port):
+        connection = Connection(conn_id="test_conn", conn_type="test", 
port=port)
+
+        assert connection.port == expected_port
+
+    @pytest.mark.parametrize("port", [-1, 0, 65536, "0", "65536", 
"not-a-port", True])
+    def test_connection_rejects_invalid_ports(self, port):
+        with pytest.raises(ValueError, match="port"):
+            Connection(conn_id="test_conn", conn_type="test", port=port)
+
+    def test_parse_from_uri_rejects_port_zero(self):
+        with pytest.raises(ValueError, match="between 1 and 65535"):
+            Connection(conn_id="test_conn", uri="type://host:0/schema")
+

Review Comment:
   Duplicate case already covered in above test
   ```suggestion
   ```



##########
airflow-core/src/airflow/models/connection.py:
##########
@@ -219,6 +222,32 @@ def _validate_extra(extra, conn_id) -> None:
             raise ValueError(f"Encountered non-JSON in `extra` field for 
connection {conn_id!r}.")
         return None
 
+    @staticmethod
+    def _coerce_port(port: int | str | None) -> int | None:
+        if port is None:
+            return None
+        if isinstance(port, bool):
+            raise ValueError(f"Expected integer value for `port`, but got 
{port!r} instead.")
+        if isinstance(port, int):
+            return port
+        if isinstance(port, str):
+            try:
+                return int(port)
+            except ValueError:
+                raise ValueError(f"Expected integer value for `port`, but got 
{port!r} instead.") from None

Review Comment:
   How do you hit this str case?



-- 
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