Repository: iterative/dvc

Issue:
add: empty files add broken when cache mode is hardlinks
## DVC Version


```
DVC version: 0.86.5+f67314.mod
Python version: 3.7.6
Platform: Darwin-18.2.0-x86_64-i386-64bit
Binary: False
Package: None
Cache: reflink - supported, hardlink - supported, symlink - supported
Filesystem type (cache directory): ('apfs', '/dev/disk1s1')
Filesystem type (workspace): ('apfs', '/dev/disk1s1')
```

## Reproduce

```
dvc config cache.type hardlink
touch foo
dvc add foo
```

outputs:

```
ERROR: no possible cache types left to try out.
```


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/iterative/dvc/pull/3428?src=pr&el=h1) Report
> Merging [#3428](https://codecov.io/gh/iterative/dvc/pull/3428?src=pr&el=desc) into [master](https://codecov.io/gh/iterative/dvc/commit/05cc023164766fbbec91642d7d8af513c8d4079b?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/iterative/dvc/pull/3428/graphs/tree.svg?width=650&token=VOfa1EJWC4&height=150&src=pr)](https://codecov.io/gh/iterative/dvc/pull/3428?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master    #3428   +/-   ##
=======================================
  Coverage   93.08%   93.08%           
=======================================
  Files         140      140           
  Lines        8515     8515           
=======================================
  Hits         7926     7926           
  Misses        589      589
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/iterative/dvc/pull/3428?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/iterative/dvc/pull/3428?src=pr&el=footer). Last update [05cc023...4e9289f](https://codecov.io/gh/iterative/dvc/pull/3428?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

skshetry: We (@efiop and I) discussed this on 1o1. A better way to fix this would be to try to create a temporary file to check if the **System** supports `{ref,hard,sym}`link. Though, it'll need some refactor, so, I'll create an issue for working on this later. 

Patch:
diff --git a/dvc/api.py b/dvc/api.py
index d1312baaf..98763d16a 100644
--- a/dvc/api.py
+++ b/dvc/api.py
@@ -7,31 +7,44 @@ from dvc.external_repo import external_repo
 
 
 class UrlNotDvcRepoError(DvcException):
-    """Thrown if given URL is not a DVC repository.
-
-    Args:
-        url (str): URL to the repository
-    """
+    """Thrown if the given URL is not a DVC repository."""
 
     def __init__(self, url):
         super().__init__("'{}' is not a DVC repository.".format(url))
 
 
 def get_url(path, repo=None, rev=None, remote=None):
-    """Returns URL to the storage location of a data artifact tracked
-    by DVC, specified by its path in a repo.
+    """
+    Returns the URL to the storage location of a data file or directory tracked
+    in a DVC repo. For Git repos, HEAD is used unless a rev argument is
+    supplied. The default remote is tried unless a remote argument is supplied.
 
-    NOTE: There's no guarantee that the file actually exists in that location.
+    Raises UrlNotDvcRepoError if repo is not a DVC project.
+
+    NOTE: This function does not check for the actual existence of the file or
+    directory in the remote storage.
     """
     with _make_repo(repo, rev=rev) as _repo:
-        _require_dvc(_repo)
+        if not isinstance(_repo, Repo):
+            raise UrlNotDvcRepoError(_repo.url)
         out = _repo.find_out_by_relpath(path)
         remote_obj = _repo.cloud.get_remote(remote)
         return str(remote_obj.checksum_to_path_info(out.checksum))
 
 
 def open(path, repo=None, rev=None, remote=None, mode="r", encoding=None):
-    """Context manager to open a tracked file as a file object."""
+    """
+    Open file in the supplied path tracked in a repo (both DVC projects and
+    plain Git repos are supported). For Git repos, HEAD is used unless a rev
+    argument is supplied. The default remote is tried unless a remote argument
+    is supplied. It may only be used as a context manager:
+
+        with dvc.api.open(
+                'path/to/file',
+                repo='https://example.com/url/to/repo'
+                ) as fd:
+            # ... Handle file object fd
+    """
     args = (path,)
     kwargs = {
         "repo": repo,
@@ -63,7 +76,11 @@ def _open(path, repo=None, rev=None, remote=None, mode="r", encoding=None):
 
 
 def read(path, repo=None, rev=None, remote=None, mode="r", encoding=None):
-    """Returns the contents of a tracked file."""
+    """
+    Returns the contents of a tracked file (by DVC or Git). For Git repos, HEAD
+    is used unless a rev argument is supplied. The default remote is tried
+    unless a remote argument is supplied.
+    """
     with open(
         path, repo=repo, rev=rev, remote=remote, mode=mode, encoding=encoding
     ) as fd:
@@ -81,8 +98,3 @@ def _make_repo(repo_url=None, rev=None):
             pass  # fallthrough to external_repo
     with external_repo(url=repo_url, rev=rev) as repo:
         yield repo
-
-
-def _require_dvc(repo):
-    if not isinstance(repo, Repo):
-        raise UrlNotDvcRepoError(repo.url)
diff --git a/dvc/config.py b/dvc/config.py
index 1d6118ec4..0907c66f3 100644
--- a/dvc/config.py
+++ b/dvc/config.py
@@ -172,9 +172,13 @@ SCHEMA = {
                     **REMOTE_COMMON,
                 },
                 "gdrive": {
+                    "gdrive_use_service_account": Bool,
                     "gdrive_client_id": str,
                     "gdrive_client_secret": str,
                     "gdrive_user_credentials_file": str,
+                    "gdrive_service_account_email": str,
+                    "gdrive_service_account_user_email": str,
+                    "gdrive_service_account_p12_file_path": str,
                     **REMOTE_COMMON,
                 },
                 "http": {**HTTP_COMMON, **REMOTE_COMMON},
@@ -201,9 +205,8 @@ class Config(dict):
         validate (bool): optional flag to tell dvc if it should validate the
             config or just load it as is. 'True' by default.
 
-
     Raises:
-        ConfigError: thrown when config has an invalid format.
+        ConfigError: thrown if config has an invalid format.
     """
 
     APPNAME = "dvc"
@@ -272,7 +275,7 @@ class Config(dict):
         """Loads config from all the config files.
 
         Raises:
-            dvc.config.ConfigError: thrown if config has invalid format.
+            ConfigError: thrown if config has an invalid format.
         """
         conf = {}
         for level in self.LEVELS:
@@ -332,7 +335,7 @@ class Config(dict):
     @contextmanager
     def edit(self, level="repo"):
         if level in {"repo", "local"} and self.dvc_dir is None:
-            raise ConfigError("Not inside a dvc repo")
+            raise ConfigError("Not inside a DVC repo")
 
         conf = self.load_one(level)
         yield conf
diff --git a/dvc/remote/gdrive.py b/dvc/remote/gdrive.py
index 80b4261bb..56499e853 100644
--- a/dvc/remote/gdrive.py
+++ b/dvc/remote/gdrive.py
@@ -76,7 +76,7 @@ class RemoteGDrive(RemoteBASE):
     DEFAULT_NO_TRAVERSE = False
     DEFAULT_VERIFY = True
 
-    GDRIVE_USER_CREDENTIALS_DATA = "GDRIVE_USER_CREDENTIALS_DATA"
+    GDRIVE_CREDENTIALS_DATA = "GDRIVE_CREDENTIALS_DATA"
     DEFAULT_USER_CREDENTIALS_FILE = "gdrive-user-credentials.json"
 
     def __init__(self, repo, config):
@@ -93,17 +93,22 @@ class RemoteGDrive(RemoteBASE):
             )
 
         self._bucket = self.path_info.bucket
+        self._use_service_account = config.get("gdrive_use_service_account")
+        self._service_account_email = config.get(
+            "gdrive_service_account_email"
+        )
+        self._service_account_user_email = config.get(
+            "gdrive_service_account_user_email"
+        )
+        self._service_account_p12_file_path = config.get(
+            "gdrive_service_account_p12_file_path"
+        )
         self._client_id = config.get("gdrive_client_id")
         self._client_secret = config.get("gdrive_client_secret")
-        if not self._client_id or not self._client_secret:
-            raise DvcException(
-                "Please specify Google Drive's client id and "
-                "secret in DVC config. Learn more at "
-                "{}.".format(format_link("https://man.dvc.org/remote/add"))
-            )
+        self._validate_config()
         self._gdrive_user_credentials_path = (
             tmp_fname(os.path.join(self.repo.tmp_dir, ""))
-            if os.getenv(RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA)
+            if os.getenv(RemoteGDrive.GDRIVE_CREDENTIALS_DATA)
             else config.get(
                 "gdrive_user_credentials_file",
                 os.path.join(
@@ -114,6 +119,33 @@ class RemoteGDrive(RemoteBASE):
 
         self._list_params = None
 
+    def _validate_config(self):
+        # Validate Service Account configuration
+        if self._use_service_account and (
+            not self._service_account_email
+            or not self._service_account_p12_file_path
+        ):
+            raise DvcException(
+                "To use service account please specify {}, {} and "
+                "{} in DVC config. Learn more at "
+                "{}.".format(
+                    "gdrive_service_account_email",
+                    "gdrive_service_account_p12_file_path",
+                    "gdrive_service_account_user_email (optional)",
+                    format_link("https://man.dvc.org/remote/modify"),
+                )
+            )
+
+        # Validate OAuth 2.0 Client ID configuration
+        if not self._use_service_account and (
+            not self._client_id or not self._client_secret
+        ):
+            raise DvcException(
+                "Please specify Google Drive's client id and "
+                "secret in DVC config. Learn more at "
+                "{}.".format(format_link("https://man.dvc.org/remote/modify"))
+            )
+
     @wrap_prop(threading.RLock())
     @cached_property
     def drive(self):
@@ -121,23 +153,30 @@ class RemoteGDrive(RemoteBASE):
         from pydrive2.auth import GoogleAuth
         from pydrive2.drive import GoogleDrive
 
-        if os.getenv(RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA):
+        if os.getenv(RemoteGDrive.GDRIVE_CREDENTIALS_DATA):
             with open(
                 self._gdrive_user_credentials_path, "w"
             ) as credentials_file:
                 credentials_file.write(
-                    os.getenv(RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA)
+                    os.getenv(RemoteGDrive.GDRIVE_CREDENTIALS_DATA)
                 )
 
         GoogleAuth.DEFAULT_SETTINGS["client_config_backend"] = "settings"
-        GoogleAuth.DEFAULT_SETTINGS["client_config"] = {
-            "client_id": self._client_id,
-            "client_secret": self._client_secret,
-            "auth_uri": "https://accounts.google.com/o/oauth2/auth",
-            "token_uri": "https://oauth2.googleapis.com/token",
-            "revoke_uri": "https://oauth2.googleapis.com/revoke",
-            "redirect_uri": "",
-        }
+        if self._use_service_account:
+            GoogleAuth.DEFAULT_SETTINGS["service_config"] = {
+                "client_service_email": self._service_account_email,
+                "client_user_email": self._service_account_user_email,
+                "client_pkcs12_file_path": self._service_account_p12_file_path,
+            }
+        else:
+            GoogleAuth.DEFAULT_SETTINGS["client_config"] = {
+                "client_id": self._client_id,
+                "client_secret": self._client_secret,
+                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+                "token_uri": "https://oauth2.googleapis.com/token",
+                "revoke_uri": "https://oauth2.googleapis.com/revoke",
+                "redirect_uri": "",
+            }
         GoogleAuth.DEFAULT_SETTINGS["save_credentials"] = True
         GoogleAuth.DEFAULT_SETTINGS["save_credentials_backend"] = "file"
         GoogleAuth.DEFAULT_SETTINGS[
@@ -153,7 +192,10 @@ class RemoteGDrive(RemoteBASE):
         gauth = GoogleAuth(settings_file="")
 
         try:
-            gauth.CommandLineAuth()
+            if self._use_service_account:
+                gauth.ServiceAuth()
+            else:
+                gauth.CommandLineAuth()
         except RefreshError as exc:
             raise GDriveAccessTokenRefreshError from exc
         except KeyError as exc:
@@ -164,7 +206,7 @@ class RemoteGDrive(RemoteBASE):
         except Exception as exc:
             raise DvcException("Google Drive authentication failed") from exc
         finally:
-            if os.getenv(RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA):
+            if os.getenv(RemoteGDrive.GDRIVE_CREDENTIALS_DATA):
                 os.remove(self._gdrive_user_credentials_path)
 
         return GoogleDrive(gauth)
diff --git a/dvc/remote/local.py b/dvc/remote/local.py
index 24725c526..3e62e0628 100644
--- a/dvc/remote/local.py
+++ b/dvc/remote/local.py
@@ -92,6 +92,12 @@ class RemoteLOCAL(RemoteBASE):
 
         return not self.changed_cache(current_md5)
 
+    def _verify_link(self, path_info, link_type):
+        if link_type == "hardlink" and self.getsize(path_info) == 0:
+            return
+
+        super()._verify_link(path_info, link_type)
+
     def is_empty(self, path_info):
         path = path_info.fspath
 
diff --git a/dvc/scm/__init__.py b/dvc/scm/__init__.py
index 62f106314..15a75796f 100644
--- a/dvc/scm/__init__.py
+++ b/dvc/scm/__init__.py
@@ -4,8 +4,8 @@ from dvc.scm.base import Base
 from dvc.scm.git import Git
 
 
-# just a sugar to point that this is an actual implementation for a dvc
-# project under no SCM control
+# Syntactic sugar to signal that this is an actual implementation for a DVC
+# project under no SCM control.
 class NoSCM(Base):
     pass
 
diff --git a/dvc/version.py b/dvc/version.py
index 48b5ae25e..b9e405ff3 100644
--- a/dvc/version.py
+++ b/dvc/version.py
@@ -7,7 +7,7 @@ import os
 import subprocess
 
 
-_BASE_VERSION = "0.87.0"
+_BASE_VERSION = "0.88.0"
 
 
 def _generate_version(base_version):
diff --git a/scripts/ci/install_hadoop.sh b/scripts/ci/install_hadoop.sh
index eaf50e977..10a42eea5 100755
--- a/scripts/ci/install_hadoop.sh
+++ b/scripts/ci/install_hadoop.sh
@@ -11,7 +11,7 @@ sudo apt-get install openjdk-7-jdk
 java -version
 
 pushd /usr/local
-sudo wget https://s3-us-west-2.amazonaws.com/dvc-share/test/hadoop-2.6.5.tar.gz
+sudo wget https://s3-us-east-2.amazonaws.com/dvc-public/travis-test/hadoop-2.6.5.tar.gz
 sudo tar xzf hadoop-2.6.5.tar.gz
 sudo mkdir hadoop
 sudo mv hadoop-2.6.5/* hadoop/
diff --git a/scripts/completion/dvc.bash b/scripts/completion/dvc.bash
index 135f70661..61b1a93eb 100644
--- a/scripts/completion/dvc.bash
+++ b/scripts/completion/dvc.bash
@@ -24,26 +24,26 @@ _dvc_destroy='-f --force'
 _dvc_diff='-t --show-json --show-hash'
 _dvc_fetch='-j --jobs -r --remote -a --all-branches -T --all-tags -d --with-deps -R --recursive'
 _dvc_fetch_COMPGEN=_dvc_compgen_DVCFiles
-_dvc_get_url=''
-_dvc_get='-o --out --rev --show-url'
 _dvc_gc='-a --all-branches --all-commits -T --all-tags -w --workspace -c --cloud -r --remote -f --force -p --projects -j --jobs'
-_dvc_import_url='-f --file'
+_dvc_get='-o --out --rev --show-url'
+_dvc_get_url=''
 _dvc_import='-o --out --rev'
+_dvc_import_url='-f --file'
 _dvc_init='--no-scm -f --force'
 _dvc_install=''
 _dvc_list='-R --recursive --outs-only --rev'
 _dvc_list_COMPGEN=_dvc_compgen_files
-_dvc_lock='$(compgen -f -X \!*?.dvc)'
-_dvc_metrics='add modify rmeove show'
+_dvc_lock=_dvc_compgen_DVCFiles
+_dvc_metrics='add diff modify remove show'
 _dvc_metrics_add='-t --type -x --xpath'
 _dvc_metrics_add_COMPGEN=_dvc_compgen_files
-_dvc_metrics_show='$(-t --type -x --xpath -a --all-branches -T --all-tags -R --recursive'
-_dvc_metrics_show_COMPGEN=_dvc_compgen_files
 _dvc_metrics_diff='--targets -t --type -x --xpath -R --show-json'
 _dvc_metrics_modify='-t --type -x --xpath'
 _dvc_metrics_modify_COMPGEN=_dvc_compgen_files
-_dvc_metrics_remove='$(compgen -f)'
-_dvc_move='$(compgen -f)'
+_dvc_metrics_remove=_dvc_compgen_files
+_dvc_metrics_show='-t --type -x --xpath -a --all-branches -T --all-tags -R --recursive'
+_dvc_metrics_show_COMPGEN=_dvc_compgen_files
+_dvc_move=_dvc_compgen_files
 _dvc_pipeline='list show'
 _dvc_pipeline_list=''
 _dvc_pipeline_show='-c --commands -o --outs --ascii --dot --tree -l --locked'
@@ -63,9 +63,10 @@ _dvc_remove_COMPGEN=_dvc_compgen_DVCFiles
 _dvc_repro='-f --force -s --single-item -c --cwd -m --metrics --dry -i --interactive -p --pipeline -P --all-pipelines --ignore-build-cache --no-commit -R --recursive --downstream'
 _dvc_repro_COMPGEN=_dvc_compgen_DVCFiles
 _dvc_root=''
-_dvc_run='--no-exec -f --file -c --cwd -d --deps -o --outs -O --outs-no-cache --outs-persist --outs-persist-no-cache -m --metrics -M --metrics-no-cache -y --yes --overwrite-dvcfile --ignore-build-cache --remove-outs --no-commit -w --wdir'
-_dvc_status='-j --jobs -r --remote -a --all-branches -T --all-tags -d --with-deps -c --cloud'
+_dvc_run='--no-exec -f --file -d --deps -o --outs -O --outs-no-cache --outs-persist --outs-persist-no-cache -m --metrics -M --metrics-no-cache --overwrite-dvcfile --ignore-build-cache --no-commit -w --wdir'
 _dvc_run_COMPGEN=_dvc_compgen_DVCFiles
+_dvc_status='-j --jobs -r --remote -a --all-branches -T --all-tags -d --with-deps -c --cloud'
+_dvc_status_COMPGEN=_dvc_compgen_DVCFiles
 _dvc_unlock_COMPGEN=_dvc_compgen_DVCFiles
 _dvc_unprotect_COMPGEN=_dvc_compgen_files
 _dvc_update='--rev'
diff --git a/setup.py b/setup.py
index 1f7f67e84..5930136a7 100644
--- a/setup.py
+++ b/setup.py
@@ -53,7 +53,7 @@ install_requires = [
     "nanotime>=0.5.2",
     "pyasn1>=0.4.1",
     "voluptuous>=0.11.7",
-    "jsonpath-ng>=1.4.3",
+    "jsonpath-ng>=1.5.1",
     "requests>=2.22.0",
     "grandalf==0.6",
     "distro>=1.3.0",
@@ -84,7 +84,7 @@ install_requires = [
 # Extra dependencies for remote integrations
 
 gs = ["google-cloud-storage==1.19.0"]
-gdrive = ["pydrive2>=1.4.5"]
+gdrive = ["pydrive2>=1.4.6"]
 s3 = ["boto3>=1.9.201"]
 azure = ["azure-storage-blob==2.1.0"]
 oss = ["oss2==2.6.1"]


Test patch:
diff --git a/tests/func/test_add.py b/tests/func/test_add.py
index 95407ee7d..9d966452d 100644
--- a/tests/func/test_add.py
+++ b/tests/func/test_add.py
@@ -7,7 +7,7 @@ import time
 
 import colorama
 import pytest
-from mock import patch
+from mock import patch, call
 
 import dvc as dvc_module
 from dvc.cache import Cache
@@ -662,3 +662,36 @@ def test_not_raises_on_re_add(tmp_dir, dvc):
 
     tmp_dir.gen({"file2": "file2 content", "file": "modified file"})
     dvc.add(["file2", "file"])
+
+
+@pytest.mark.parametrize("link", ["hardlink", "symlink", "copy"])
+def test_add_empty_files(tmp_dir, dvc, link):
+    file = "foo"
+    dvc.cache.local.cache_types = [link]
+    stages = tmp_dir.dvc_gen(file, "")
+
+    assert (tmp_dir / file).exists()
+    assert (tmp_dir / (file + Stage.STAGE_FILE_SUFFIX)).exists()
+    assert os.path.exists(stages[0].outs[0].cache_path)
+
+
+def test_add_optimization_for_hardlink_on_empty_files(tmp_dir, dvc, mocker):
+    dvc.cache.local.cache_types = ["hardlink"]
+    tmp_dir.gen({"foo": "", "bar": "", "lorem": "lorem", "ipsum": "ipsum"})
+    m = mocker.spy(RemoteLOCAL, "is_hardlink")
+    stages = dvc.add(["foo", "bar", "lorem", "ipsum"])
+
+    assert m.call_count == 1
+    assert m.call_args != call(tmp_dir / "foo")
+    assert m.call_args != call(tmp_dir / "bar")
+
+    for stage in stages[:2]:
+        # hardlinks are not created for empty files
+        assert not System.is_hardlink(stage.outs[0].path_info)
+
+    for stage in stages[2:]:
+        assert System.is_hardlink(stage.outs[0].path_info)
+
+    for stage in stages:
+        assert os.path.exists(stage.path)
+        assert os.path.exists(stage.outs[0].cache_path)
diff --git a/tests/func/test_data_cloud.py b/tests/func/test_data_cloud.py
index b28c2e438..aaf1a12c5 100644
--- a/tests/func/test_data_cloud.py
+++ b/tests/func/test_data_cloud.py
@@ -37,8 +37,6 @@ from tests.remotes import (
     OSS,
     TEST_CONFIG,
     TEST_GCP_CREDS_FILE,
-    TEST_GDRIVE_CLIENT_ID,
-    TEST_GDRIVE_CLIENT_SECRET,
     TEST_REMOTE,
 )
 
@@ -193,8 +191,9 @@ def setup_gdrive_cloud(remote_url, dvc):
     config = copy.deepcopy(TEST_CONFIG)
     config["remote"][TEST_REMOTE] = {
         "url": remote_url,
-        "gdrive_client_id": TEST_GDRIVE_CLIENT_ID,
-        "gdrive_client_secret": TEST_GDRIVE_CLIENT_SECRET,
+        "gdrive_service_account_email": "test",
+        "gdrive_service_account_p12_file_path": "test.p12",
+        "gdrive_use_service_account": True,
     }
 
     dvc.config = config
@@ -434,8 +433,8 @@ class TestRemoteGDriveCLI(GDrive, TestDataCloudCLIBase):
                 "remote",
                 "modify",
                 TEST_REMOTE,
-                "gdrive_client_id",
-                TEST_GDRIVE_CLIENT_ID,
+                "gdrive_service_account_email",
+                "modified",
             ]
         )
         self.main(
@@ -443,8 +442,17 @@ class TestRemoteGDriveCLI(GDrive, TestDataCloudCLIBase):
                 "remote",
                 "modify",
                 TEST_REMOTE,
-                "gdrive_client_secret",
-                TEST_GDRIVE_CLIENT_SECRET,
+                "gdrive_service_account_p12_file_path",
+                "modified.p12",
+            ]
+        )
+        self.main(
+            [
+                "remote",
+                "modify",
+                TEST_REMOTE,
+                "gdrive_use_service_account",
+                "True",
             ]
         )
 
diff --git a/tests/remotes.py b/tests/remotes.py
index 55029312d..a80619b17 100644
--- a/tests/remotes.py
+++ b/tests/remotes.py
@@ -35,11 +35,6 @@ TEST_GCP_CREDS_FILE = os.path.abspath(
 # Ensure that absolute path is used
 os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = TEST_GCP_CREDS_FILE
 
-TEST_GDRIVE_CLIENT_ID = (
-    "217948389181-rs7it4a635b3qrf8dnmklmoj2kimun9n.apps.googleusercontent.com"
-)
-TEST_GDRIVE_CLIENT_SECRET = "LNg9n_cK7bohI8gEHn4bUeMX"
-
 always_test = staticmethod(lambda: True)
 
 
@@ -146,7 +141,7 @@ class GCP:
 class GDrive:
     @staticmethod
     def should_test():
-        return os.getenv(RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA) is not None
+        return os.getenv(RemoteGDrive.GDRIVE_CREDENTIALS_DATA) is not None
 
     def get_url(self):
         if not getattr(self, "_remote_url", None):
diff --git a/tests/unit/remote/test_gdrive.py b/tests/unit/remote/test_gdrive.py
index 9d7c511e1..e165903cc 100644
--- a/tests/unit/remote/test_gdrive.py
+++ b/tests/unit/remote/test_gdrive.py
@@ -33,15 +33,15 @@ class TestRemoteGDrive(object):
     def test_drive(self):
         remote = RemoteGDrive(Repo(), self.CONFIG)
         os.environ[
-            RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA
+            RemoteGDrive.GDRIVE_CREDENTIALS_DATA
         ] = USER_CREDS_TOKEN_REFRESH_ERROR
         with pytest.raises(GDriveAccessTokenRefreshError):
             remote.drive
 
-        os.environ[RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA] = ""
+        os.environ[RemoteGDrive.GDRIVE_CREDENTIALS_DATA] = ""
         remote = RemoteGDrive(Repo(), self.CONFIG)
         os.environ[
-            RemoteGDrive.GDRIVE_USER_CREDENTIALS_DATA
+            RemoteGDrive.GDRIVE_CREDENTIALS_DATA
         ] = USER_CREDS_MISSED_KEY_ERROR
         with pytest.raises(GDriveMissedCredentialKeyError):
             remote.drive