Repository: googleapis/python-firestore

Issue:
Emulator with Anonymous Credentials is No Longer Possible
Previously on version `1.9.0`, setting the environment variable `FIRESTORE_EMULATOR_HOST` and providing `AnonymousCredentials` allowed the transport to be established successfully.

After upgrading to `2.0.0`, we are receiving a `DefaultCredentialsError` instead. When `FIRESTORE_EMULATOR_HOST` is set, the credentials provided to the client are no longer respected.

#### Environment details
Running an instance of the Firestore emulator inside of a Docker container

  - OS type and version: CentOS 7.5
  - Python version: 3.8
  - pip version: 20.2
  - `google-cloud-firestore` version: 2.0.0
  - `google-auth` version: 1.23.0

#### Steps to reproduce

  1. Set `FIRESTORE_EMULATOR_HOST` environment variable `e.g. FIRESTORE_EMULATOR_HOST=emulator_host:8200`
  2. Instantiate a new Firestore client by providing `AnonymousCredentials`
  3. Execute an example query/request using this client

#### Code example

```python
# e.g. export FIRESTORE_EMULATOR_HOST=emulator_host:8200

from google.auth.credentials import AnonymousCredentials
from google.cloud.firestore import Client

credentials = AnonymousCredentials()
client = Client(project="my-project", credentials=credentials)

product = db.collection("products").document("product_abcd").get()

print(product)
```

#### Stack trace
```
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/cloud/firestore_v1/document.py", line 359, in get
  firestore_api = self._client._firestore_api
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/cloud/firestore_v1/client.py", line 104, in _firestore_api
  return self._firestore_api_helper(
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/cloud/firestore_v1/base_client.py", line 152, in _firestore_api_helper
  channel = transport.create_channel(host=self._emulator_host)
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/cloud/firestore_v1/services/firestore/transports/grpc.py", line 223, in create_channel
  return grpc_helpers.create_channel(
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/api_core/grpc_helpers.py", line 275, in create_channel
  composite_credentials = _create_composite_credentials(
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/api_core/grpc_helpers.py", line 217, in _create_composite_credentials
  credentials, _ = google.auth.default(scopes=scopes)
File "/pyenv/versions/test-app/lib/python3.8/site-packages/google/auth/_default.py", line 356, in default
  raise exceptions.DefaultCredentialsError(_HELP_MESSAGE)

google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, please see https://cloud.google.com/docs/authentication/getting-started
```


Discussion:

Patch:
diff --git a/google/cloud/firestore_v1/base_client.py b/google/cloud/firestore_v1/base_client.py
index f532ec1..7b9b228 100644
--- a/google/cloud/firestore_v1/base_client.py
+++ b/google/cloud/firestore_v1/base_client.py
@@ -25,6 +25,7 @@ In the hierarchy of API concepts
 """
 
 import os
+import grpc  # type: ignore
 
 import google.api_core.client_options  # type: ignore
 import google.api_core.path_template  # type: ignore
@@ -147,9 +148,7 @@ class BaseClient(ClientWithProject):
             # We need this in order to set appropriate keepalive options.
 
             if self._emulator_host is not None:
-                # TODO(microgen): this likely needs to be adapted to use insecure_channel
-                # on new generated surface.
-                channel = transport.create_channel(host=self._emulator_host)
+                channel = grpc.insecure_channel(self._emulator_host)
             else:
                 channel = transport.create_channel(
                     self._target,
diff --git a/noxfile.py b/noxfile.py
index 0f79223..567f6bd 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -27,10 +27,11 @@ PYTYPE_VERSION = "pytype==2020.7.24"
 BLACK_VERSION = "black==19.10b0"
 BLACK_PATHS = ["docs", "google", "tests", "noxfile.py", "setup.py"]
 
-DEFAULT_PYTHON_VERSION = "3.9"
-SYSTEM_TEST_PYTHON_VERSIONS = ["3.9"]
+DEFAULT_PYTHON_VERSION = "3.8"
+SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"]
 UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"]
 
+
 @nox.session(python=DEFAULT_PYTHON_VERSION)
 def lint(session):
     """Run linters.
@@ -98,6 +99,7 @@ def default(session):
         *session.posargs,
     )
 
+
 @nox.session(python=UNIT_TEST_PYTHON_VERSIONS)
 def unit(session):
     """Run the unit test suite."""


Test patch:
diff --git a/tests/unit/v1/test_base_client.py b/tests/unit/v1/test_base_client.py
index 631733e..163ea33 100644
--- a/tests/unit/v1/test_base_client.py
+++ b/tests/unit/v1/test_base_client.py
@@ -67,8 +67,7 @@ class TestBaseClient(unittest.TestCase):
         return_value=mock.sentinel.firestore_api,
     )
     @mock.patch(
-        "google.cloud.firestore_v1.services.firestore.transports.grpc.FirestoreGrpcTransport.create_channel",
-        autospec=True,
+        "grpc.insecure_channel", autospec=True,
     )
     def test__firestore_api_property_with_emulator(
         self, mock_insecure_channel, mock_client
@@ -83,7 +82,7 @@ class TestBaseClient(unittest.TestCase):
         self.assertIs(firestore_api, mock_client.return_value)
         self.assertIs(firestore_api, client._firestore_api_internal)
 
-        mock_insecure_channel.assert_called_once_with(host=emulator_host)
+        mock_insecure_channel.assert_called_once_with(emulator_host)
 
         # Call again to show that it is cached, but call count is still 1.
         self.assertIs(client._firestore_api, mock_client.return_value)