Repository: googleapis/python-pubsub (language: python)

Issue:
Fix flaky tests in test_publisher_client caused due to non-deterministic number of spans exported by OpenTelemetry
Fix error:
```
=================================== FAILURES ===================================
__________________ test_opentelemetry_flow_control_exception ___________________

creds = 
span_exporter = 

    @pytest.mark.skipif(
        sys.version_info < (3, 8),
        reason="Open Telemetry not supported below Python version 3.8",
    )
    def test_opentelemetry_flow_control_exception(creds, span_exporter):
        publisher_options = types.PublisherOptions(
            flow_control=types.PublishFlowControl(
                message_limit=10,
                byte_limit=150,
                limit_exceeded_behavior=types.LimitExceededBehavior.ERROR,
            ),
            enable_open_telemetry_tracing=True,
        )
        client = publisher.Client(credentials=creds, publisher_options=publisher_options)
    
        mock_batch = mock.Mock(spec=client._batch_class)
        topic = "projects/projectID/topics/topicID"
        client._set_batch(topic, mock_batch)
    
        future1 = client.publish(topic, b"a" * 60)
        future2 = client.publish(topic, b"b" * 100)
    
        future1.result()  # no error, still within flow control limits
        with pytest.raises(exceptions.FlowControlLimitError):
            future2.result()
    
        spans = span_exporter.get_finished_spans()
        # Span 1 = Publisher Flow Control Span of first publish
        # Span 2 = Publisher Batching Span of first publish
        # Span 3 = Publisher Flow Control Span of second publish(raises FlowControlLimitError)
        # Span 4 = Publish Create Span of second publish(raises FlowControlLimitError)
>       assert len(spans) == 4
E       assert 5 == 4
E        +  where 5 = len((, , ))

tests/unit/pubsub_v1/publisher/test_publisher_client.py:294: AssertionError
- generated xml file: /tmpfs/src/github/python-pubsub/unit_3.12_sponge_log.xml -
=========================== short test summary info ============================
```


Discussion / hints:

Fix patch:
diff --git a/noxfile.py b/noxfile.py
index 2ccbfeae7..47611cdff 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -55,7 +55,9 @@
 UNIT_TEST_EXTERNAL_DEPENDENCIES: List[str] = []
 UNIT_TEST_LOCAL_DEPENDENCIES: List[str] = []
 UNIT_TEST_DEPENDENCIES: List[str] = []
-UNIT_TEST_EXTRAS: List[str] = []
+UNIT_TEST_EXTRAS: List[str] = [
+    "flaky",
+]
 UNIT_TEST_EXTRAS_BY_PYTHON: Dict[str, List[str]] = {}
 
 SYSTEM_TEST_PYTHON_VERSIONS: List[str] = ["3.12"]
diff --git a/owlbot.py b/owlbot.py
index 2e4b00bc9..77eb08250 100644
--- a/owlbot.py
+++ b/owlbot.py
@@ -337,6 +337,7 @@
     cov_level=100,
     versions=gcp.common.detect_versions(path="./google", default_first=True),
     unit_test_python_versions=["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"],
+    unit_test_extras=["flaky"],
     system_test_python_versions=["3.12"],
     system_test_external_dependencies=["psutil","flaky"],
 )
diff --git a/setup.py b/setup.py
index abe06552b..fb2b94fad 100644
--- a/setup.py
+++ b/setup.py
@@ -50,7 +50,7 @@
     "opentelemetry-sdk <= 1.22.0; python_version<='3.7'",
     "opentelemetry-sdk >= 1.27.0; python_version>='3.8'",
 ]
-extras = {"libcst": "libcst >= 0.3.10"}
+extras = {"libcst": "libcst >= 0.3.10,", "flaky": "flaky"}
 url = "https://github.com/googleapis/python-pubsub"
 
 package_root = os.path.abspath(os.path.dirname(__file__))


Test patch:
diff --git a/tests/unit/pubsub_v1/publisher/test_publisher_client.py b/tests/unit/pubsub_v1/publisher/test_publisher_client.py
index abc33f8cb..55198b590 100644
--- a/tests/unit/pubsub_v1/publisher/test_publisher_client.py
+++ b/tests/unit/pubsub_v1/publisher/test_publisher_client.py
@@ -28,6 +28,8 @@
 
 import pytest
 import time
+from flaky import flaky
+from typing import cast, Callable, Any, TypeVar
 
 from opentelemetry import trace
 from google.api_core import gapic_v1
@@ -49,6 +51,10 @@
 )
 
 
+C = TypeVar("C", bound=Callable[..., Any])
+typed_flaky = cast(Callable[[C], C], flaky(max_runs=5, min_passes=1))
+
+
 def _assert_retries_equal(retry, retry2):
     # Retry instances cannot be directly compared, because their predicates are
     # different instances of the same function. We thus manually compare their other
@@ -142,6 +148,7 @@ def test_init_w_custom_transport(creds):
         False,
     ],
 )
+@typed_flaky
 def test_open_telemetry_publisher_options(creds, enable_open_telemetry):
     if sys.version_info >= (3, 8) or enable_open_telemetry is False:
         client = publisher.Client(