Repository: apache/airflow

Issue:
Can't clear all upstream tasks when DAG Serialization is enabled

**Apache Airflow version**: 1.10.10



**To Reproduce**
Steps to reproduce the behavior with Astronomer Image:
1. Enable DAG Serialization (Put `AIRFLOW__CORE__STORE_SERIALIZED_DAGS=True`
Once the Webserver boots up, run any DAG
1. Once the DAG completes execution, click on the task that has few upstream tasks in Graph View
1. One the **Task Instance Modal**, select **Upstream** -> click on **Clear**. You will see a list of tasks but that would not have all the upstream tasks.

**Screenshots**
![Apr-22-2020 15-56-14](https://user-images.githubusercontent.com/8811558/79997805-d96b7f00-84b1-11ea-8328-9d24c4a77ad6.gif)





Discussion:
I think I have a fix for this

Resolving patch:
diff --git a/airflow/providers/google/cloud/example_dags/example_gcs.py b/airflow/providers/google/cloud/example_dags/example_gcs.py
--- a/airflow/providers/google/cloud/example_dags/example_gcs.py
+++ b/airflow/providers/google/cloud/example_dags/example_gcs.py
@@ -126,8 +126,8 @@
     )
 
     # [START howto_operator_gcs_delete_bucket]
-    delete_bucket_1 = GCSDeleteBucketOperator(task_id="delete_bucket", bucket_name=BUCKET_1)
-    delete_bucket_2 = GCSDeleteBucketOperator(task_id="delete_bucket", bucket_name=BUCKET_2)
+    delete_bucket_1 = GCSDeleteBucketOperator(task_id="delete_bucket_1", bucket_name=BUCKET_1)
+    delete_bucket_2 = GCSDeleteBucketOperator(task_id="delete_bucket_2", bucket_name=BUCKET_2)
     # [END howto_operator_gcs_delete_bucket]
 
     [create_bucket1, create_bucket2] >> list_buckets >> list_buckets_result
diff --git a/airflow/serialization/serialized_objects.py b/airflow/serialization/serialized_objects.py
--- a/airflow/serialization/serialized_objects.py
+++ b/airflow/serialization/serialized_objects.py
@@ -598,7 +598,7 @@ def deserialize_dag(cls, encoded_dag: Dict[str, Any]) -> 'SerializedDAG':
             for task_id in serializable_task.downstream_task_ids:
                 # Bypass set_upstream etc here - it does more than we want
                 # noinspection PyProtectedMember
-                dag.task_dict[task_id]._upstream_task_ids.add(task_id)  # pylint: disable=protected-access
+                dag.task_dict[task_id]._upstream_task_ids.add(serializable_task.task_id)  # noqa: E501 # pylint: disable=protected-access
 
         return dag
 


Test patch:
diff --git a/tests/serialization/test_dag_serialization.py b/tests/serialization/test_dag_serialization.py
--- a/tests/serialization/test_dag_serialization.py
+++ b/tests/serialization/test_dag_serialization.py
@@ -355,6 +355,9 @@ def validate_deserialized_task(self, serialized_task, task,):
         assert serialized_task.task_type == task.task_type
         assert set(serialized_task.template_fields) == set(task.template_fields)
 
+        assert serialized_task.upstream_task_ids == task.upstream_task_ids
+        assert serialized_task.downstream_task_ids == task.downstream_task_ids
+
         for field in fields_to_check:
             assert getattr(serialized_task, field) == getattr(task, field), \
                 f'{task.dag.dag_id}.{task.task_id}.{field} does not match'