| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,25 +18,22 @@ | |||
| 18 | 18 | from google.cloud._storage_v2.services.storage.transports.base import ( | |
| 19 | 19 | DEFAULT_CLIENT_INFO, | |
| 20 | 20 | ) | |
| 21 | + from google.cloud.storage import __version__ | ||
| 21 | 22 | ||
| 22 | 23 | ||
| 23 | 24 | class AsyncGrpcClient: | |
| 24 | 25 | """An asynchronous client for interacting with Google Cloud Storage using the gRPC API. | |
| 25 | - | ||
| 26 | 26 | :type credentials: :class:`~google.auth.credentials.Credentials` | |
| 27 | 27 | :param credentials: (Optional) The OAuth2 Credentials to use for this | |
| 28 | 28 | client. If not passed, falls back to the default | |
| 29 | 29 | inferred from the environment. | |
| 30 | - | ||
| 31 | 30 | :type client_info: :class:`~google.api_core.client_info.ClientInfo` | |
| 32 | 31 | :param client_info: | |
| 33 | 32 | The client info used to send a user-agent string along with API | |
| 34 | 33 | requests. If ``None``, then default info will be used. | |
| 35 | - | ||
| 36 | 34 | :type client_options: :class:`~google.api_core.client_options.ClientOptions` | |
| 37 | 35 | :param client_options: (Optional) Client options used to set user options | |
| 38 | 36 | on the client. | |
| 39 | - | ||
| 40 | 37 | :type attempt_direct_path: bool | |
| 41 | 38 | :param attempt_direct_path: | |
| 42 | 39 | (Optional) Whether to attempt to use DirectPath for gRPC connections. | |
@@ -51,6 +48,18 @@ def __init__( | |||
| 51 | 48 | *, | |
| 52 | 49 | attempt_direct_path=True, | |
| 53 | 50 | ): | |
| 51 | + if client_info is None: | ||
| 52 | + client_info = DEFAULT_CLIENT_INFO | ||
| 53 | + else: | ||
| 54 | + client_info = client_info | ||
| 55 | + client_info.client_library_version = __version__ | ||
| 56 | + # TODO: When metrics all use gccl, this should be removed #9552 | ||
| 57 | + if client_info.user_agent is None: # pragma: no branch | ||
| 58 | + client_info.user_agent = "" | ||
| 59 | + agent_version = f"gcloud-python/{__version__}" | ||
| 60 | + if agent_version not in client_info.user_agent: | ||
| 61 | + client_info.user_agent += f" {agent_version} " | ||
| 62 | + | ||
| 54 | 63 | self._grpc_client = self._create_async_grpc_client( | |
| 55 | 64 | credentials=credentials, | |
| 56 | 65 | client_info=client_info, | |
@@ -69,8 +78,6 @@ def _create_async_grpc_client( | |||
| 69 | 78 | "grpc_asyncio" | |
| 70 | 79 | ) | |
| 71 | 80 | ||
| 72 | - if client_info is None: | ||
| 73 | - client_info = DEFAULT_CLIENT_INFO | ||
| 74 | 81 | primary_user_agent = client_info.to_user_agent() | |
| 75 | 82 | ||
| 76 | 83 | channel = transport_cls.create_channel( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,10 +16,8 @@ | |||
| 16 | 16 | from google.auth import credentials as auth_credentials | |
| 17 | 17 | from google.auth.credentials import AnonymousCredentials | |
| 18 | 18 | from google.api_core import client_info as client_info_lib | |
| 19 | + from google.cloud.storage import __version__ | ||
| 19 | 20 | from google.cloud.storage._experimental.asyncio import async_grpc_client | |
| 20 | - from google.cloud.storage._experimental.asyncio.async_grpc_client import ( | ||
| 21 | - DEFAULT_CLIENT_INFO, | ||
| 22 | - ) | ||
| 23 | 21 | ||
| 24 | 22 | ||
| 25 | 23 | def _make_credentials(spec=None): | |
@@ -36,16 +34,20 @@ def test_constructor_default_options(self, mock_async_storage_client): | |||
| 36 | 34 | mock_async_storage_client.get_transport_class.return_value = mock_transport_cls | |
| 37 | 35 | mock_creds = _make_credentials() | |
| 38 | 36 | ||
| 39 | - primary_user_agent = DEFAULT_CLIENT_INFO.to_user_agent() | ||
| 40 | - expected_options = (("grpc.primary_user_agent", primary_user_agent),) | ||
| 41 | - | ||
| 42 | 37 | # Act | |
| 43 | 38 | async_grpc_client.AsyncGrpcClient(credentials=mock_creds) | |
| 44 | 39 | ||
| 45 | 40 | # Assert | |
| 46 | 41 | mock_async_storage_client.get_transport_class.assert_called_once_with( | |
| 47 | 42 | "grpc_asyncio" | |
| 48 | 43 | ) | |
| 44 | + kwargs = mock_async_storage_client.call_args.kwargs | ||
| 45 | + client_info = kwargs["client_info"] | ||
| 46 | + agent_version = f"gcloud-python/{__version__}" | ||
| 47 | + assert agent_version in client_info.user_agent | ||
| 48 | + primary_user_agent = client_info.to_user_agent() | ||
| 49 | + expected_options = (("grpc.primary_user_agent", primary_user_agent),) | ||
| 50 | + | ||
| 49 | 51 | mock_transport_cls.create_channel.assert_called_once_with( | |
| 50 | 52 | attempt_direct_path=True, | |
| 51 | 53 | credentials=mock_creds, | |
@@ -54,11 +56,8 @@ def test_constructor_default_options(self, mock_async_storage_client): | |||
| 54 | 56 | mock_channel = mock_transport_cls.create_channel.return_value | |
| 55 | 57 | mock_transport_cls.assert_called_once_with(channel=mock_channel) | |
| 56 | 58 | mock_transport = mock_transport_cls.return_value | |
| 57 | - mock_async_storage_client.assert_called_once_with( | ||
| 58 | - transport=mock_transport, | ||
| 59 | - client_options=None, | ||
| 60 | - client_info=DEFAULT_CLIENT_INFO, | ||
| 61 | - ) | ||
| 59 | + assert kwargs["transport"] is mock_transport | ||
| 60 | + assert kwargs["client_options"] is None | ||
| 62 | 61 | ||
| 63 | 62 | @mock.patch("google.cloud._storage_v2.StorageAsyncClient") | |
| 64 | 63 | def test_constructor_with_client_info(self, mock_async_storage_client): | |
@@ -73,6 +72,8 @@ def test_constructor_with_client_info(self, mock_async_storage_client): | |||
| 73 | 72 | credentials=mock_creds, client_info=client_info | |
| 74 | 73 | ) | |
| 75 | 74 | ||
| 75 | + agent_version = f"gcloud-python/{__version__}" | ||
| 76 | + assert agent_version in client_info.user_agent | ||
| 76 | 77 | primary_user_agent = client_info.to_user_agent() | |
| 77 | 78 | expected_options = (("grpc.primary_user_agent", primary_user_agent),) | |
| 78 | 79 | ||
@@ -92,7 +93,11 @@ def test_constructor_disables_directpath(self, mock_async_storage_client): | |||
| 92 | 93 | credentials=mock_creds, attempt_direct_path=False | |
| 93 | 94 | ) | |
| 94 | 95 | ||
| 95 | - primary_user_agent = DEFAULT_CLIENT_INFO.to_user_agent() | ||
| 96 | + kwargs = mock_async_storage_client.call_args.kwargs | ||
| 97 | + client_info = kwargs["client_info"] | ||
| 98 | + agent_version = f"gcloud-python/{__version__}" | ||
| 99 | + assert agent_version in client_info.user_agent | ||
| 100 | + primary_user_agent = client_info.to_user_agent() | ||
| 96 | 101 | expected_options = (("grpc.primary_user_agent", primary_user_agent),) | |
| 97 | 102 | ||
| 98 | 103 | mock_transport_cls.create_channel.assert_called_once_with( | |
@@ -109,43 +114,43 @@ def test_grpc_client_property(self, mock_grpc_gapic_client): | |||
| 109 | 114 | mock_transport_cls = mock.MagicMock() | |
| 110 | 115 | mock_grpc_gapic_client.get_transport_class.return_value = mock_transport_cls | |
| 111 | 116 | channel_sentinel = mock.sentinel.channel | |
| 112 | - | ||
| 113 | 117 | mock_transport_cls.create_channel.return_value = channel_sentinel | |
| 114 | - mock_transport_cls.return_value = mock.sentinel.transport | ||
| 118 | + mock_transport_instance = mock.sentinel.transport | ||
| 119 | + mock_transport_cls.return_value = mock_transport_instance | ||
| 115 | 120 | ||
| 116 | 121 | mock_creds = _make_credentials() | |
| 117 | - mock_client_info = mock.MagicMock(spec=client_info_lib.ClientInfo) | ||
| 118 | - mock_client_info.to_user_agent.return_value = "test-user-agent" | ||
| 122 | + # Use a real ClientInfo instance instead of a mock to properly test user agent logic | ||
| 123 | + client_info = client_info_lib.ClientInfo(user_agent="test-user-agent") | ||
| 119 | 124 | mock_client_options = mock.sentinel.client_options | |
| 120 | 125 | mock_attempt_direct_path = mock.sentinel.attempt_direct_path | |
| 121 | 126 | ||
| 122 | 127 | # Act | |
| 123 | 128 | client = async_grpc_client.AsyncGrpcClient( | |
| 124 | 129 | credentials=mock_creds, | |
| 125 | - client_info=mock_client_info, | ||
| 130 | + client_info=client_info, | ||
| 126 | 131 | client_options=mock_client_options, | |
| 127 | 132 | attempt_direct_path=mock_attempt_direct_path, | |
| 128 | 133 | ) | |
| 134 | + retrieved_client = client.grpc_client # This is what is being tested | ||
| 129 | 135 | ||
| 130 | - mock_grpc_gapic_client.get_transport_class.return_value = mock_transport_cls | ||
| 136 | + # Assert - verify that gcloud-python agent version was added | ||
| 137 | + agent_version = f"gcloud-python/{__version__}" | ||
| 138 | + assert agent_version in client_info.user_agent | ||
| 139 | + # Also verify original user_agent is still there | ||
| 140 | + assert "test-user-agent" in client_info.user_agent | ||
| 131 | 141 | ||
| 132 | - mock_transport_cls.create_channel.return_value = channel_sentinel | ||
| 133 | - mock_transport_instance = mock.sentinel.transport | ||
| 134 | - mock_transport_cls.return_value = mock_transport_instance | ||
| 135 | - | ||
| 136 | - retrieved_client = client.grpc_client | ||
| 142 | + primary_user_agent = client_info.to_user_agent() | ||
| 143 | + expected_options = (("grpc.primary_user_agent", primary_user_agent),) | ||
| 137 | 144 | ||
| 138 | - # Assert | ||
| 139 | - expected_options = (("grpc.primary_user_agent", "test-user-agent"),) | ||
| 140 | 145 | mock_transport_cls.create_channel.assert_called_once_with( | |
| 141 | 146 | attempt_direct_path=mock_attempt_direct_path, | |
| 142 | 147 | credentials=mock_creds, | |
| 143 | 148 | options=expected_options, | |
| 144 | 149 | ) | |
| 145 | - mock_transport_cls.assere_with(channel=channel_sentinel) | ||
| 150 | + mock_transport_cls.assert_called_once_with(channel=channel_sentinel) | ||
| 146 | 151 | mock_grpc_gapic_client.assert_called_once_with( | |
| 147 | 152 | transport=mock_transport_instance, | |
| 148 | - client_info=mock_client_info, | ||
| 153 | + client_info=client_info, | ||
| 149 | 154 | client_options=mock_client_options, | |
| 150 | 155 | ) | |
| 151 | 156 | assert retrieved_client is mock_grpc_gapic_client.return_value | |
@@ -168,12 +173,39 @@ def test_grpc_client_with_anon_creds(self, mock_grpc_gapic_client): | |||
| 168 | 173 | # Assert | |
| 169 | 174 | assert retrieved_client is mock_grpc_gapic_client.return_value | |
| 170 | 175 | ||
| 171 | - primary_user_agent = DEFAULT_CLIENT_INFO.to_user_agent() | ||
| 176 | + kwargs = mock_grpc_gapic_client.call_args.kwargs | ||
| 177 | + client_info = kwargs["client_info"] | ||
| 178 | + agent_version = f"gcloud-python/{__version__}" | ||
| 179 | + assert agent_version in client_info.user_agent | ||
| 180 | + primary_user_agent = client_info.to_user_agent() | ||
| 172 | 181 | expected_options = (("grpc.primary_user_agent", primary_user_agent),) | |
| 173 | 182 | ||
| 174 | 183 | mock_transport_cls.create_channel.assert_called_once_with( | |
| 175 | 184 | attempt_direct_path=True, | |
| 176 | 185 | credentials=anonymous_creds, | |
| 177 | 186 | options=expected_options, | |
| 178 | 187 | ) | |
| 179 | - mock_transport_cls.assert_called_once_with(channel=channel_sentinel) | ||
| 188 | + | ||
| 189 | + @mock.patch("google.cloud._storage_v2.StorageAsyncClient") | ||
| 190 | + def test_user_agent_with_custom_client_info(self, mock_async_storage_client): | ||
| 191 | + """Test that gcloud-python user agent is appended to existing user agent. | ||
| 192 | + | ||
| 193 | + Regression test similar to test__http.py::TestConnection::test_duplicate_user_agent | ||
| 194 | + """ | ||
| 195 | + mock_transport_cls = mock.MagicMock() | ||
| 196 | + mock_async_storage_client.get_transport_class.return_value = mock_transport_cls | ||
| 197 | + mock_creds = _make_credentials() | ||
| 198 | + | ||
| 199 | + # Create a client_info with an existing user_agent | ||
| 200 | + client_info = client_info_lib.ClientInfo(user_agent="custom-app/1.0") | ||
| 201 | + | ||
| 202 | + # Act | ||
| 203 | + async_grpc_client.AsyncGrpcClient( | ||
| 204 | + credentials=mock_creds, | ||
| 205 | + client_info=client_info, | ||
| 206 | + ) | ||
| 207 | + | ||
| 208 | + # Assert - verify that gcloud-python version was appended | ||
| 209 | + agent_version = f"gcloud-python/{__version__}" | ||
| 210 | + expected_user_agent = f"custom-app/1.0 {agent_version} " | ||
| 211 | + assert client_info.user_agent == expected_user_agent | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments