This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 9caede9a418 Add missing test for 
amazon/aws/executors/ecs/boto_schema.py (#54930)
9caede9a418 is described below

commit 9caede9a4181a1f2e7a3ef6f367a9095be765b62
Author: yangyulely <[email protected]>
AuthorDate: Tue Aug 26 19:03:50 2025 +0800

    Add missing test for amazon/aws/executors/ecs/boto_schema.py (#54930)
---
 .../tests/unit/always/test_project_structure.py    |   1 -
 .../amazon/aws/executors/ecs/test_boto_schema.py   | 232 +++++++++++++++++++++
 2 files changed, 232 insertions(+), 1 deletion(-)

diff --git a/airflow-core/tests/unit/always/test_project_structure.py 
b/airflow-core/tests/unit/always/test_project_structure.py
index 48b9de6fc5c..093c3417da8 100644
--- a/airflow-core/tests/unit/always/test_project_structure.py
+++ b/airflow-core/tests/unit/always/test_project_structure.py
@@ -66,7 +66,6 @@ class TestProjectStructure:
             
"providers/amazon/tests/unit/amazon/aws/executors/batch/test_batch_executor_config.py",
             
"providers/amazon/tests/unit/amazon/aws/executors/batch/test_boto_schema.py",
             
"providers/amazon/tests/unit/amazon/aws/executors/batch/test_utils.py",
-            
"providers/amazon/tests/unit/amazon/aws/executors/ecs/test_boto_schema.py",
             
"providers/amazon/tests/unit/amazon/aws/executors/ecs/test_ecs_executor_config.py",
             
"providers/amazon/tests/unit/amazon/aws/executors/ecs/test_utils.py",
             
"providers/amazon/tests/unit/amazon/aws/executors/aws_lambda/test_utils.py",
diff --git 
a/providers/amazon/tests/unit/amazon/aws/executors/ecs/test_boto_schema.py 
b/providers/amazon/tests/unit/amazon/aws/executors/ecs/test_boto_schema.py
new file mode 100644
index 00000000000..34988bc139b
--- /dev/null
+++ b/providers/amazon/tests/unit/amazon/aws/executors/ecs/test_boto_schema.py
@@ -0,0 +1,232 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from __future__ import annotations
+
+from datetime import datetime
+
+from airflow.providers.amazon.aws.executors.ecs.boto_schema import (
+    BotoContainerSchema,
+    BotoDescribeTasksSchema,
+    BotoFailureSchema,
+    BotoRunTaskSchema,
+    BotoTaskSchema,
+)
+from airflow.providers.amazon.aws.executors.ecs.utils import EcsExecutorTask
+
+
+class TestBotoSchema:
+    def test_boto_container_schema_load(self):
+        schema = BotoContainerSchema()
+        data = {
+            "exitCode": 0,
+            "lastStatus": "STOPPED",
+            "name": "test_container",
+            "reason": "Essential container in task exited",
+            "containerArn": 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/1234567890abcdef0",
+        }
+        result = schema.load(data)
+        assert result["exit_code"] == 0
+        assert result["last_status"] == "STOPPED"
+        assert result["name"] == "test_container"
+        assert result["reason"] == "Essential container in task exited"
+        assert (
+            result["container_arn"]
+            == 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/1234567890abcdef0"
+        )
+
+    def test_boto_container_schema_load_minimal(self):
+        schema = BotoContainerSchema()
+        data = {"name": "minimal_container"}
+        result = schema.load(data)
+        assert result["name"] == "minimal_container"
+        assert result.get("exit_code") is None
+        assert result.get("last_status") is None
+        assert result.get("reason") is None
+        assert result.get("container_arn") is None
+
+    def test_boto_container_schema_exclude_unknown(self):
+        schema = BotoContainerSchema()
+        data = {"name": "test_container", "unknownField": "should_be_ignored"}
+        result = schema.load(data)
+        assert "unknownField" not in result
+
+    def test_boto_task_schema_load(self):
+        schema = BotoTaskSchema()
+        container_data = {
+            "exitCode": 0,
+            "lastStatus": "STOPPED",
+            "name": "test_container",
+            "reason": "Essential container in task exited",
+            "containerArn": 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/1234567890abcdef0",
+        }
+        data = {
+            "taskArn": 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0",
+            "lastStatus": "STOPPED",
+            "desiredStatus": "STOPPED",
+            "containers": [container_data],
+            "startedAt": datetime(2023, 1, 1),
+            "stoppedReason": "Task failed to start",
+        }
+        result = schema.load(data)
+        assert isinstance(result, EcsExecutorTask)
+        assert result.task_arn == 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0"
+        assert result.last_status == "STOPPED"
+        assert result.desired_status == "STOPPED"
+        assert len(result.containers) == 1
+        assert result.containers[0]["name"] == "test_container"
+        assert result.started_at == datetime(2023, 1, 1)
+        assert result.stopped_reason == "Task failed to start"
+
+    def test_boto_task_schema_load_minimal(self):
+        schema = BotoTaskSchema()
+        container_data = {"name": "minimal_container_in_task"}
+        data = {
+            "taskArn": 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0",
+            "lastStatus": "RUNNING",
+            "desiredStatus": "RUNNING",
+            "containers": [container_data],
+        }
+        result = schema.load(data)
+        assert isinstance(result, EcsExecutorTask)
+        assert result.task_arn == 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0"
+        assert result.last_status == "RUNNING"
+        assert result.desired_status == "RUNNING"
+        assert len(result.containers) == 1
+        assert result.containers[0]["name"] == "minimal_container_in_task"
+        assert result.started_at is None
+        assert result.stopped_reason is None
+
+    def test_boto_task_schema_exclude_unknown(self):
+        schema = BotoTaskSchema()
+        container_data = {"name": "test_container"}
+        data = {
+            "taskArn": 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0",
+            "lastStatus": "RUNNING",
+            "desiredStatus": "RUNNING",
+            "containers": [container_data],
+            "unknownTaskField": "should_be_ignored",
+        }
+        result = schema.load(data)
+        # EcsExecutorTask doesn't store unknown fields, so we check the 
deserialized dict before object creation
+        # by checking the raw data passed to EcsExecutorTask constructor if 
possible,
+        # or simply ensure no error occurs and the object is created.
+        # A more direct way would be to mock EcsExecutorTask and inspect its 
kwargs.
+        # For now, we just ensure it loads without error and produces the 
correct type.
+        assert isinstance(result, EcsExecutorTask)
+
+    def test_boto_failure_schema_load(self):
+        schema = BotoFailureSchema()
+        data = {
+            "arn": 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/1234567890abcdef0",
+            "reason": "MISSING",
+        }
+        result = schema.load(data)
+        assert result["arn"] == 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/1234567890abcdef0"
+        assert result["reason"] == "MISSING"
+
+    def test_boto_failure_schema_load_minimal(self):
+        schema = BotoFailureSchema()
+        data = {}
+        result = schema.load(data)
+        assert result.get("arn") is None
+        assert result.get("reason") is None
+
+    def test_boto_failure_schema_exclude_unknown(self):
+        schema = BotoFailureSchema()
+        data = {"arn": "test_arn", "unknownField": "should_be_ignored"}
+        result = schema.load(data)
+        assert "unknownField" not in result
+
+    def test_boto_run_task_schema_load(self):
+        schema = BotoRunTaskSchema()
+        task_data = {
+            "taskArn": 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0",
+            "lastStatus": "RUNNING",
+            "desiredStatus": "RUNNING",
+            "containers": [{"name": "test_container"}],
+        }
+        failure_data = {
+            "arn": 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/badabcdef0",
+            "reason": "MISSING",
+        }
+        data = {"tasks": [task_data], "failures": [failure_data]}
+        result = schema.load(data)
+
+        assert len(result["tasks"]) == 1
+        assert isinstance(result["tasks"][0], EcsExecutorTask)
+        assert (
+            result["tasks"][0].task_arn
+            == 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef0"
+        )
+
+        assert len(result["failures"]) == 1
+        assert (
+            result["failures"][0]["arn"]
+            == 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/badabcdef0"
+        )
+        assert result["failures"][0]["reason"] == "MISSING"
+
+    def test_boto_run_task_schema_exclude_unknown(self):
+        schema = BotoRunTaskSchema()
+        data = {
+            "tasks": [],
+            "failures": [],
+            "unknownRunTaskField": "should_be_ignored",
+        }
+        result = schema.load(data)
+        assert "unknownRunTaskField" not in result
+
+    def test_boto_describe_tasks_schema_load(self):
+        schema = BotoDescribeTasksSchema()
+        task_data = {
+            "taskArn": 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef1",
+            "lastStatus": "STOPPED",
+            "desiredStatus": "STOPPED",
+            "containers": [{"name": "another_container", "exitCode": 1}],
+        }
+        failure_data = {
+            "arn": 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/anotherbad",
+            "reason": "UNABLE",
+        }
+        data = {"tasks": [task_data], "failures": [failure_data]}
+        result = schema.load(data)
+
+        assert len(result["tasks"]) == 1
+        assert isinstance(result["tasks"][0], EcsExecutorTask)
+        assert (
+            result["tasks"][0].task_arn
+            == 
"arn:aws:ecs:us-east-1:123456789012:task/test-cluster/1234567890abcdef1"
+        )
+        assert result["tasks"][0].containers[0]["exit_code"] == 1
+
+        assert len(result["failures"]) == 1
+        assert (
+            result["failures"][0]["arn"]
+            == 
"arn:aws:ecs:us-east-1:123456789012:container/test-cluster/anotherbad"
+        )
+        assert result["failures"][0]["reason"] == "UNABLE"
+
+    def test_boto_describe_tasks_schema_exclude_unknown(self):
+        schema = BotoDescribeTasksSchema()
+        data = {
+            "tasks": [],
+            "failures": [],
+            "unknownDescribeTasksField": "should_be_ignored",
+        }
+        result = schema.load(data)
+        assert "unknownDescribeTasksField" not in result

Reply via email to