Add File Watcher Certificate Provider API
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5bfb16b..5d07b41 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -830,6 +830,7 @@
   add_dependencies(buildtests_cxx google_mesh_ca_certificate_provider_factory_test)
   add_dependencies(buildtests_cxx grpc_cli)
   add_dependencies(buildtests_cxx grpc_tls_certificate_distributor_test)
+  add_dependencies(buildtests_cxx grpc_tls_certificate_provider_test)
   add_dependencies(buildtests_cxx grpc_tls_credentials_options_test)
   if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
     add_dependencies(buildtests_cxx grpc_tool_test)
@@ -11696,6 +11697,7 @@
 
 add_executable(grpc_tls_certificate_distributor_test
   test/core/security/grpc_tls_certificate_distributor_test.cc
+  test/core/security/tls_utils.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
@@ -11732,8 +11734,48 @@
 endif()
 if(gRPC_BUILD_TESTS)
 
+add_executable(grpc_tls_certificate_provider_test
+  test/core/security/grpc_tls_certificate_provider_test.cc
+  test/core/security/tls_utils.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(grpc_tls_certificate_provider_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(grpc_tls_certificate_provider_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc
+  gpr
+  address_sorting
+  upb
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
 add_executable(grpc_tls_credentials_options_test
   test/core/security/grpc_tls_credentials_options_test.cc
+  test/core/security/tls_utils.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
 )
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index cd73d4b..4e94a38 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -6208,9 +6208,26 @@
   gtest: true
   build: test
   language: c++
-  headers: []
+  headers:
+  - test/core/security/tls_utils.h
   src:
   - test/core/security/grpc_tls_certificate_distributor_test.cc
+  - test/core/security/tls_utils.cc
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr
+  - address_sorting
+  - upb
+- name: grpc_tls_certificate_provider_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - test/core/security/tls_utils.h
+  src:
+  - test/core/security/grpc_tls_certificate_provider_test.cc
+  - test/core/security/tls_utils.cc
   deps:
   - grpc_test_util
   - grpc
@@ -6221,9 +6238,11 @@
   gtest: true
   build: test
   language: c++
-  headers: []
+  headers:
+  - test/core/security/tls_utils.h
   src:
   - test/core/security/grpc_tls_credentials_options_test.cc
+  - test/core/security/tls_utils.cc
   deps:
   - grpc_test_util
   - grpc
diff --git a/grpc.def b/grpc.def
index aecf99a..1328923 100644
--- a/grpc.def
+++ b/grpc.def
@@ -139,6 +139,7 @@
     grpc_tls_identity_pairs_add_pair
     grpc_tls_identity_pairs_destroy
     grpc_tls_certificate_provider_static_data_create
+    grpc_tls_certificate_provider_file_watcher_create
     grpc_tls_certificate_provider_release
     grpc_tls_credentials_options_create
     grpc_tls_credentials_options_set_cert_request_type
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 12f39ec..1482d7c 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -808,6 +808,31 @@
     const char* root_certificate, grpc_tls_identity_pairs* pem_key_cert_pairs);
 
 /**
+ * Creates a grpc_tls_certificate_provider that will watch the credential
+ * changes on the file system. This provider will always return the up-to-date
+ * cert data for all the cert names callers set through
+ * |grpc_tls_credentials_options|. Note that this API only supports one key-cert
+ * file and hence one set of identity key-cert pair, so SNI(Server Name
+ * Indication) is not supported.
+ * - private_key_path is the file path of the private key. This must be set if
+ *   |identity_certificate_path| is set. Otherwise, it could be null if no
+ *   identity credentials are needed.
+ * - identity_certificate_path is the file path of the identity certificate
+ *   chain. This must be set if |private_key_path| is set. Otherwise, it could
+ *   be null if no identity credentials are needed.
+ * - root_cert_path is the file path to the root certificate bundle. This
+ *   may be null if no root certs are needed.
+ * - refresh_interval_sec is the refreshing interval that we will check the
+ *   files for updates.
+ * It does not take ownership of parameters.
+ * It is used for experimental purpose for now and subject to change.
+ */
+GRPCAPI grpc_tls_certificate_provider*
+grpc_tls_certificate_provider_file_watcher_create(
+    const char* private_key_path, const char* identity_certificate_path,
+    const char* root_cert_path, unsigned int refresh_interval_sec);
+
+/**
  * Releases a grpc_tls_certificate_provider object. The creator of the
  * grpc_tls_certificate_provider object is responsible for its release. It is
  * used for experimental purpose for now and subject to change.
diff --git a/include/grpcpp/security/tls_certificate_provider.h b/include/grpcpp/security/tls_certificate_provider.h
index 797687c..ec006f3 100644
--- a/include/grpcpp/security/tls_certificate_provider.h
+++ b/include/grpcpp/security/tls_certificate_provider.h
@@ -66,7 +66,57 @@
       const std::vector<IdentityKeyCertPair>& identity_key_cert_pairs)
       : StaticDataCertificateProvider("", identity_key_cert_pairs) {}
 
-  ~StaticDataCertificateProvider();
+  ~StaticDataCertificateProvider() override;
+
+  grpc_tls_certificate_provider* c_provider() override { return c_provider_; }
+
+ private:
+  grpc_tls_certificate_provider* c_provider_ = nullptr;
+};
+
+// A CertificateProviderInterface implementation that will watch the credential
+// changes on the file system. This provider will always return the up-to-date
+// cert data for all the cert names callers set through |TlsCredentialsOptions|.
+// Several things to note:
+// 1. This API only supports one key-cert file and hence one set of identity
+// key-cert pair, so SNI(Server Name Indication) is not supported.
+// 2. The private key and identity certificate should always match. This API
+// guarantees atomic read, and it is the callers' responsibility to do atomic
+// updates. There are many ways to atomically update the key and certs in the
+// file system. To name a few:
+//   1)  creating a new directory, renaming the old directory to a new name, and
+//   then renaming the new directory to the original name of the old directory.
+//   2)  using a symlink for the directory. When need to change, put new
+//   credential data in a new directory, and change symlink.
+class FileWatcherCertificateProvider final
+    : public CertificateProviderInterface {
+ public:
+  // Constructor to get credential updates from root and identity file paths.
+  //
+  // @param private_key_path is the file path of the private key.
+  // @param identity_certificate_path is the file path of the identity
+  // certificate chain.
+  // @param root_cert_path is the file path to the root certificate bundle.
+  // @param refresh_interval_sec is the refreshing interval that we will check
+  // the files for updates.
+  FileWatcherCertificateProvider(const std::string& private_key_path,
+                                 const std::string& identity_certificate_path,
+                                 const std::string& root_cert_path,
+                                 unsigned int refresh_interval_sec);
+  // Constructor to get credential updates from identity file paths only.
+  FileWatcherCertificateProvider(const std::string& private_key_path,
+                                 const std::string& identity_certificate_path,
+                                 unsigned int refresh_interval_sec)
+      : FileWatcherCertificateProvider(private_key_path,
+                                       identity_certificate_path, "",
+                                       refresh_interval_sec) {}
+  // Constructor to get credential updates from root file path only.
+  FileWatcherCertificateProvider(const std::string& root_cert_path,
+                                 unsigned int refresh_interval_sec)
+      : FileWatcherCertificateProvider("", "", root_cert_path,
+                                       refresh_interval_sec) {}
+
+  ~FileWatcherCertificateProvider() override;
 
   grpc_tls_certificate_provider* c_provider() override { return c_provider_; }
 
diff --git a/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h b/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
index 35451e7..9ce9443 100644
--- a/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
+++ b/src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h
@@ -72,12 +72,7 @@
                          grpc_error* identity_cert_error) = 0;
   };
 
-  // Sets the key materials based on their certificate name. Note that we are
-  // not doing any copies for pem_root_certs and pem_key_cert_pairs. For
-  // pem_root_certs, the original string contents need to outlive the
-  // distributor; for pem_key_cert_pairs, internally it is taking two
-  // unique_ptr(s) to the credential string, so the ownership is actually
-  // transferred.
+  // Sets the key materials based on their certificate name.
   //
   // @param cert_name The name of the certificates being updated.
   // @param pem_root_certs The content of root certificates.
diff --git a/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc b/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
index 80ea4ea..9e69d98 100644
--- a/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
+++ b/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc
@@ -22,6 +22,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/gprpp/stat.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/api_trace.h"
 
 namespace grpc_core {
@@ -35,20 +37,334 @@
   distributor_->SetWatchStatusCallback([this](std::string cert_name,
                                               bool root_being_watched,
                                               bool identity_being_watched) {
-    if (!root_being_watched && !identity_being_watched) return;
+    grpc_core::MutexLock lock(&mu_);
     absl::optional<std::string> root_certificate;
     absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
-    if (root_being_watched) {
+    StaticDataCertificateProvider::WatcherInfo& info = watcher_info_[cert_name];
+    if (!info.root_being_watched && root_being_watched &&
+        !root_certificate_.empty()) {
       root_certificate = root_certificate_;
     }
-    if (identity_being_watched) {
+    info.root_being_watched = root_being_watched;
+    if (!info.identity_being_watched && identity_being_watched &&
+        !pem_key_cert_pairs_.empty()) {
       pem_key_cert_pairs = pem_key_cert_pairs_;
     }
-    distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
-                                  std::move(pem_key_cert_pairs));
+    info.identity_being_watched = identity_being_watched;
+    if (!info.root_being_watched && !info.identity_being_watched) {
+      watcher_info_.erase(cert_name);
+    }
+    const bool root_has_update = root_certificate.has_value();
+    const bool identity_has_update = pem_key_cert_pairs.has_value();
+    if (root_has_update || identity_has_update) {
+      distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
+                                    std::move(pem_key_cert_pairs));
+    }
+    grpc_error* root_cert_error = GRPC_ERROR_NONE;
+    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    if (root_being_watched && !root_has_update) {
+      root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "Unable to get latest root certificates.");
+    }
+    if (identity_being_watched && !identity_has_update) {
+      identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "Unable to get latest identity certificates.");
+    }
+    if (root_cert_error != GRPC_ERROR_NONE ||
+        identity_cert_error != GRPC_ERROR_NONE) {
+      distributor_->SetErrorForCert(cert_name, root_cert_error,
+                                    identity_cert_error);
+    }
   });
 }
 
+StaticDataCertificateProvider::~StaticDataCertificateProvider() {
+  // Reset distributor's callback to make sure the callback won't be invoked
+  // again after this object(provider) is destroyed.
+  distributor_->SetWatchStatusCallback(nullptr);
+}
+
+namespace {
+
+gpr_timespec TimeoutSecondsToDeadline(int64_t seconds) {
+  return gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                      gpr_time_from_seconds(seconds, GPR_TIMESPAN));
+}
+
+}  // namespace
+
+FileWatcherCertificateProvider::FileWatcherCertificateProvider(
+    std::string private_key_path, std::string identity_certificate_path,
+    std::string root_cert_path, unsigned int refresh_interval_sec)
+    : private_key_path_(std::move(private_key_path)),
+      identity_certificate_path_(std::move(identity_certificate_path)),
+      root_cert_path_(std::move(root_cert_path)),
+      refresh_interval_sec_(refresh_interval_sec),
+      distributor_(MakeRefCounted<grpc_tls_certificate_distributor>()) {
+  // Private key and identity cert files must be both set or both unset.
+  GPR_ASSERT(private_key_path_.empty() == identity_certificate_path_.empty());
+  // Must be watching either root or identity certs.
+  GPR_ASSERT(!private_key_path_.empty() || !root_cert_path_.empty());
+  gpr_event_init(&shutdown_event_);
+  ForceUpdate();
+  auto thread_lambda = [](void* arg) {
+    FileWatcherCertificateProvider* provider =
+        static_cast<FileWatcherCertificateProvider*>(arg);
+    GPR_ASSERT(provider != nullptr);
+    while (true) {
+      void* value = gpr_event_wait(
+          &provider->shutdown_event_,
+          TimeoutSecondsToDeadline(provider->refresh_interval_sec_));
+      if (value != nullptr) {
+        return;
+      };
+      provider->ForceUpdate();
+    }
+  };
+  refresh_thread_ = grpc_core::Thread(
+      "FileWatcherCertificateProvider_refreshing_thread", thread_lambda, this);
+  refresh_thread_.Start();
+  distributor_->SetWatchStatusCallback([this](std::string cert_name,
+                                              bool root_being_watched,
+                                              bool identity_being_watched) {
+    grpc_core::MutexLock lock(&mu_);
+    absl::optional<std::string> root_certificate;
+    absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
+    FileWatcherCertificateProvider::WatcherInfo& info =
+        watcher_info_[cert_name];
+    if (!info.root_being_watched && root_being_watched &&
+        !root_certificate_.empty()) {
+      root_certificate = root_certificate_;
+    }
+    info.root_being_watched = root_being_watched;
+    if (!info.identity_being_watched && identity_being_watched &&
+        !pem_key_cert_pairs_.empty()) {
+      pem_key_cert_pairs = pem_key_cert_pairs_;
+    }
+    info.identity_being_watched = identity_being_watched;
+    if (!info.root_being_watched && !info.identity_being_watched) {
+      watcher_info_.erase(cert_name);
+    }
+    ExecCtx exec_ctx;
+    if (root_certificate.has_value() || pem_key_cert_pairs.has_value()) {
+      distributor_->SetKeyMaterials(cert_name, root_certificate,
+                                    pem_key_cert_pairs);
+    }
+    grpc_error* root_cert_error = GRPC_ERROR_NONE;
+    grpc_error* identity_cert_error = GRPC_ERROR_NONE;
+    if (root_being_watched && !root_certificate.has_value()) {
+      root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "Unable to get latest root certificates.");
+    }
+    if (identity_being_watched && !pem_key_cert_pairs.has_value()) {
+      identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+          "Unable to get latest identity certificates.");
+    }
+    if (root_cert_error != GRPC_ERROR_NONE ||
+        identity_cert_error != GRPC_ERROR_NONE) {
+      distributor_->SetErrorForCert(cert_name, root_cert_error,
+                                    identity_cert_error);
+    }
+  });
+}
+
+FileWatcherCertificateProvider::~FileWatcherCertificateProvider() {
+  // Reset distributor's callback to make sure the callback won't be invoked
+  // again after this object(provider) is destroyed.
+  distributor_->SetWatchStatusCallback(nullptr);
+  gpr_event_set(&shutdown_event_, (void*)(1));
+  refresh_thread_.Join();
+}
+
+void FileWatcherCertificateProvider::ForceUpdate() {
+  absl::optional<std::string> root_certificate;
+  absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
+  if (!root_cert_path_.empty()) {
+    root_certificate = ReadRootCertificatesFromFile(root_cert_path_);
+  }
+  if (!private_key_path_.empty()) {
+    pem_key_cert_pairs = ReadIdentityKeyCertPairFromFiles(
+        private_key_path_, identity_certificate_path_);
+  }
+  grpc_core::MutexLock lock(&mu_);
+  const bool root_cert_changed =
+      (!root_certificate.has_value() && !root_certificate_.empty()) ||
+      (root_certificate.has_value() && root_certificate_ != *root_certificate);
+  if (root_cert_changed) {
+    if (root_certificate.has_value()) {
+      root_certificate_ = std::move(*root_certificate);
+    } else {
+      root_certificate_ = "";
+    }
+  }
+  const bool identity_cert_changed =
+      (!pem_key_cert_pairs.has_value() && !pem_key_cert_pairs_.empty()) ||
+      (pem_key_cert_pairs.has_value() &&
+       pem_key_cert_pairs_ != *pem_key_cert_pairs);
+  if (identity_cert_changed) {
+    if (pem_key_cert_pairs.has_value()) {
+      pem_key_cert_pairs_ = std::move(*pem_key_cert_pairs);
+    } else {
+      pem_key_cert_pairs_ = {};
+    }
+  }
+  if (root_cert_changed || identity_cert_changed) {
+    ExecCtx exec_ctx;
+    grpc_error* root_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Unable to get latest root certificates.");
+    grpc_error* identity_cert_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+        "Unable to get latest identity certificates.");
+    for (const auto& p : watcher_info_) {
+      const std::string& cert_name = p.first;
+      const WatcherInfo& info = p.second;
+      absl::optional<std::string> root_to_report;
+      absl::optional<grpc_core::PemKeyCertPairList> identity_to_report;
+      // Set key materials to the distributor if their contents changed.
+      if (info.root_being_watched && !root_certificate_.empty() &&
+          root_cert_changed) {
+        root_to_report = root_certificate_;
+      }
+      if (info.identity_being_watched && !pem_key_cert_pairs_.empty() &&
+          identity_cert_changed) {
+        identity_to_report = pem_key_cert_pairs_;
+      }
+      if (root_to_report.has_value() || identity_to_report.has_value()) {
+        distributor_->SetKeyMaterials(cert_name, std::move(root_to_report),
+                                      std::move(identity_to_report));
+      }
+      // Report errors to the distributor if the contents are empty.
+      const bool report_root_error =
+          info.root_being_watched && root_certificate_.empty();
+      const bool report_identity_error =
+          info.identity_being_watched && pem_key_cert_pairs_.empty();
+      if (report_root_error || report_identity_error) {
+        distributor_->SetErrorForCert(
+            cert_name,
+            report_root_error ? GRPC_ERROR_REF(root_cert_error)
+                              : GRPC_ERROR_NONE,
+            report_identity_error ? GRPC_ERROR_REF(identity_cert_error)
+                                  : GRPC_ERROR_NONE);
+      }
+    }
+    GRPC_ERROR_UNREF(root_cert_error);
+    GRPC_ERROR_UNREF(identity_cert_error);
+  }
+}
+
+absl::optional<std::string>
+FileWatcherCertificateProvider::ReadRootCertificatesFromFile(
+    const std::string& root_cert_full_path) {
+  // Read the root file.
+  grpc_slice root_slice = grpc_empty_slice();
+  grpc_error* root_error =
+      grpc_load_file(root_cert_full_path.c_str(), 0, &root_slice);
+  if (root_error != GRPC_ERROR_NONE) {
+    gpr_log(GPR_ERROR, "Reading file %s failed: %s",
+            root_cert_full_path.c_str(), grpc_error_string(root_error));
+    GRPC_ERROR_UNREF(root_error);
+    return absl::nullopt;
+  }
+  std::string root_cert(StringViewFromSlice(root_slice));
+  grpc_slice_unref_internal(root_slice);
+  return root_cert;
+}
+
+namespace {
+
+// This helper function gets the last-modified time of |filename|. When failed,
+// it logs the error and returns 0.
+time_t GetModificationTime(const char* filename) {
+  time_t ts = 0;
+  absl::Status status = grpc_core::GetFileModificationTime(filename, &ts);
+  return ts;
+}
+
+}  // namespace
+
+absl::optional<PemKeyCertPairList>
+FileWatcherCertificateProvider::ReadIdentityKeyCertPairFromFiles(
+    const std::string& private_key_path,
+    const std::string& identity_certificate_path) {
+  struct SliceWrapper {
+    grpc_slice slice = grpc_empty_slice();
+    ~SliceWrapper() { grpc_slice_unref_internal(slice); }
+  };
+  const int kNumRetryAttempts = 3;
+  for (int i = 0; i < kNumRetryAttempts; ++i) {
+    // TODO(ZhenLian): replace the timestamp approach with key-match approach
+    //  once the latter is implemented.
+    // Checking the last modification of identity files before reading.
+    time_t identity_key_ts_before =
+        GetModificationTime(private_key_path.c_str());
+    if (identity_key_ts_before == 0) {
+      gpr_log(
+          GPR_ERROR,
+          "Failed to get the file's modification time of %s. Start retrying...",
+          private_key_path.c_str());
+      continue;
+    }
+    time_t identity_cert_ts_before =
+        GetModificationTime(identity_certificate_path.c_str());
+    if (identity_cert_ts_before == 0) {
+      gpr_log(
+          GPR_ERROR,
+          "Failed to get the file's modification time of %s. Start retrying...",
+          identity_certificate_path.c_str());
+      continue;
+    }
+    // Read the identity files.
+    SliceWrapper key_slice, cert_slice;
+    grpc_error* key_error =
+        grpc_load_file(private_key_path.c_str(), 0, &key_slice.slice);
+    if (key_error != GRPC_ERROR_NONE) {
+      gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
+              private_key_path.c_str(), grpc_error_string(key_error));
+      GRPC_ERROR_UNREF(key_error);
+      continue;
+    }
+    grpc_error* cert_error =
+        grpc_load_file(identity_certificate_path.c_str(), 0, &cert_slice.slice);
+    if (cert_error != GRPC_ERROR_NONE) {
+      gpr_log(GPR_ERROR, "Reading file %s failed: %s. Start retrying...",
+              identity_certificate_path.c_str(), grpc_error_string(cert_error));
+      GRPC_ERROR_UNREF(cert_error);
+      continue;
+    }
+    std::string private_key(StringViewFromSlice(key_slice.slice));
+    std::string cert_chain(StringViewFromSlice(cert_slice.slice));
+    grpc_ssl_pem_key_cert_pair* ssl_pair =
+        static_cast<grpc_ssl_pem_key_cert_pair*>(
+            gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
+    ssl_pair->private_key = gpr_strdup(private_key.c_str());
+    ssl_pair->cert_chain = gpr_strdup(cert_chain.c_str());
+    PemKeyCertPairList identity_pairs;
+    identity_pairs.emplace_back(ssl_pair);
+    // Checking the last modification of identity files before reading.
+    time_t identity_key_ts_after =
+        GetModificationTime(private_key_path.c_str());
+    if (identity_key_ts_before != identity_key_ts_after) {
+      gpr_log(GPR_ERROR,
+              "Last modified time before and after reading %s is not the same. "
+              "Start retrying...",
+              private_key_path.c_str());
+      continue;
+    }
+    time_t identity_cert_ts_after =
+        GetModificationTime(identity_certificate_path.c_str());
+    if (identity_cert_ts_before != identity_cert_ts_after) {
+      gpr_log(GPR_ERROR,
+              "Last modified time before and after reading %s is not the same. "
+              "Start retrying...",
+              identity_certificate_path.c_str());
+      continue;
+    }
+    return identity_pairs;
+  }
+  gpr_log(GPR_ERROR,
+          "All retry attempts failed. Will try again after the next interval.");
+  return absl::nullopt;
+}
+
 }  // namespace grpc_core
 
 /** -- Wrapper APIs declared in grpc_security.h -- **/
@@ -69,6 +385,16 @@
       std::move(root_cert_core), std::move(identity_pairs_core));
 }
 
+grpc_tls_certificate_provider*
+grpc_tls_certificate_provider_file_watcher_create(
+    const char* private_key_path, const char* identity_certificate_path,
+    const char* root_cert_path, unsigned int refresh_interval_sec) {
+  return new grpc_core::FileWatcherCertificateProvider(
+      private_key_path == nullptr ? "" : private_key_path,
+      identity_certificate_path == nullptr ? "" : identity_certificate_path,
+      root_cert_path == nullptr ? "" : root_cert_path, refresh_interval_sec);
+}
+
 void grpc_tls_certificate_provider_release(
     grpc_tls_certificate_provider* provider) {
   GRPC_API_TRACE("grpc_tls_certificate_provider_release(provider=%p)", 1,
diff --git a/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h b/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h
index dae6fd2..20fbb16 100644
--- a/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h
+++ b/src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h
@@ -26,6 +26,8 @@
 
 #include "src/core/lib/gprpp/ref_counted.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/gprpp/thd.h"
+#include "src/core/lib/iomgr/load_file.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.h"
 #include "src/core/lib/security/security_connector/ssl_utils.h"
@@ -59,14 +61,76 @@
       std::string root_certificate,
       grpc_core::PemKeyCertPairList pem_key_cert_pairs);
 
+  ~StaticDataCertificateProvider() override;
+
   RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
     return distributor_;
   }
 
  private:
+  struct WatcherInfo {
+    bool root_being_watched = false;
+    bool identity_being_watched = false;
+  };
   RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
   std::string root_certificate_;
   grpc_core::PemKeyCertPairList pem_key_cert_pairs_;
+  // Guards members below.
+  grpc_core::Mutex mu_;
+  // Stores each cert_name we get from the distributor callback and its watcher
+  // information.
+  std::map<std::string, WatcherInfo> watcher_info_;
+};
+
+// A provider class that will watch the credential changes on the file system.
+class FileWatcherCertificateProvider final
+    : public grpc_tls_certificate_provider {
+ public:
+  FileWatcherCertificateProvider(std::string private_key_path,
+                                 std::string identity_certificate_path,
+                                 std::string root_cert_path,
+                                 unsigned int refresh_interval_sec);
+
+  ~FileWatcherCertificateProvider() override;
+
+  RefCountedPtr<grpc_tls_certificate_distributor> distributor() const override {
+    return distributor_;
+  }
+
+ private:
+  struct WatcherInfo {
+    bool root_being_watched = false;
+    bool identity_being_watched = false;
+  };
+  // Force an update from the file system regardless of the interval.
+  void ForceUpdate();
+  // Read the root certificates from files and update the distributor.
+  absl::optional<std::string> ReadRootCertificatesFromFile(
+      const std::string& root_cert_full_path);
+  // Read the root certificates from files and update the distributor.
+  absl::optional<PemKeyCertPairList> ReadIdentityKeyCertPairFromFiles(
+      const std::string& private_key_file_name,
+      const std::string& identity_certificate_file_name);
+
+  // Information that is used by the refreshing thread.
+  std::string private_key_path_;
+  std::string identity_certificate_path_;
+  std::string root_cert_path_;
+  unsigned int refresh_interval_sec_ = 0;
+
+  RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
+  grpc_core::Thread refresh_thread_;
+  gpr_event shutdown_event_;
+
+  // Guards members below.
+  grpc_core::Mutex mu_;
+  // The most-recent credential data. It will be empty if the most recent read
+  // attempt failed.
+  std::string root_certificate_;
+  grpc_core::PemKeyCertPairList pem_key_cert_pairs_;
+  // Stores each cert_name we get from the distributor callback and its watcher
+  // information.
+  std::map<std::string, WatcherInfo> watcher_info_;
 };
 
 }  // namespace grpc_core
diff --git a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
index c672384..2aae29b 100644
--- a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
+++ b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h
@@ -147,7 +147,6 @@
     server_authorization_check_config_ = std::move(config);
   }
   // Sets the provider in the options.
-  // This should only be used by C-core API for Tls*Creds case.
   void set_certificate_provider(
       grpc_core::RefCountedPtr<grpc_tls_certificate_provider> provider) {
     provider_ = std::move(provider);
diff --git a/src/core/lib/security/security_connector/tls/tls_security_connector.h b/src/core/lib/security/security_connector/tls/tls_security_connector.h
index d915959..453c531 100644
--- a/src/core/lib/security/security_connector/tls/tls_security_connector.h
+++ b/src/core/lib/security/security_connector/tls/tls_security_connector.h
@@ -74,13 +74,12 @@
     return client_handshaker_factory_;
   };
 
-  const absl::optional<absl::string_view>& RootCertsForTesting() {
+  absl::optional<absl::string_view> RootCertsForTesting() {
     grpc_core::MutexLock lock(&mu_);
     return pem_root_certs_;
   }
 
-  const absl::optional<grpc_core::PemKeyCertPairList>&
-  KeyCertPairListForTesting() {
+  absl::optional<grpc_core::PemKeyCertPairList> KeyCertPairListForTesting() {
     grpc_core::MutexLock lock(&mu_);
     return pem_key_cert_pair_list_;
   }
diff --git a/src/cpp/common/tls_certificate_provider.cc b/src/cpp/common/tls_certificate_provider.cc
index 3550e28..2deea5f 100644
--- a/src/cpp/common/tls_certificate_provider.cc
+++ b/src/cpp/common/tls_certificate_provider.cc
@@ -41,5 +41,19 @@
   grpc_tls_certificate_provider_release(c_provider_);
 };
 
+FileWatcherCertificateProvider::FileWatcherCertificateProvider(
+    const std::string& private_key_path,
+    const std::string& identity_certificate_path,
+    const std::string& root_cert_path, unsigned int refresh_interval_sec) {
+  c_provider_ = grpc_tls_certificate_provider_file_watcher_create(
+      private_key_path.c_str(), identity_certificate_path.c_str(),
+      root_cert_path.c_str(), refresh_interval_sec);
+  GPR_ASSERT(c_provider_ != nullptr);
+};
+
+FileWatcherCertificateProvider::~FileWatcherCertificateProvider() {
+  grpc_tls_certificate_provider_release(c_provider_);
+};
+
 }  // namespace experimental
 }  // namespace grpc
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 9024a8e..90b23ae 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -162,6 +162,7 @@
 grpc_tls_identity_pairs_add_pair_type grpc_tls_identity_pairs_add_pair_import;
 grpc_tls_identity_pairs_destroy_type grpc_tls_identity_pairs_destroy_import;
 grpc_tls_certificate_provider_static_data_create_type grpc_tls_certificate_provider_static_data_create_import;
+grpc_tls_certificate_provider_file_watcher_create_type grpc_tls_certificate_provider_file_watcher_create_import;
 grpc_tls_certificate_provider_release_type grpc_tls_certificate_provider_release_import;
 grpc_tls_credentials_options_create_type grpc_tls_credentials_options_create_import;
 grpc_tls_credentials_options_set_cert_request_type_type grpc_tls_credentials_options_set_cert_request_type_import;
@@ -440,6 +441,7 @@
   grpc_tls_identity_pairs_add_pair_import = (grpc_tls_identity_pairs_add_pair_type) GetProcAddress(library, "grpc_tls_identity_pairs_add_pair");
   grpc_tls_identity_pairs_destroy_import = (grpc_tls_identity_pairs_destroy_type) GetProcAddress(library, "grpc_tls_identity_pairs_destroy");
   grpc_tls_certificate_provider_static_data_create_import = (grpc_tls_certificate_provider_static_data_create_type) GetProcAddress(library, "grpc_tls_certificate_provider_static_data_create");
+  grpc_tls_certificate_provider_file_watcher_create_import = (grpc_tls_certificate_provider_file_watcher_create_type) GetProcAddress(library, "grpc_tls_certificate_provider_file_watcher_create");
   grpc_tls_certificate_provider_release_import = (grpc_tls_certificate_provider_release_type) GetProcAddress(library, "grpc_tls_certificate_provider_release");
   grpc_tls_credentials_options_create_import = (grpc_tls_credentials_options_create_type) GetProcAddress(library, "grpc_tls_credentials_options_create");
   grpc_tls_credentials_options_set_cert_request_type_import = (grpc_tls_credentials_options_set_cert_request_type_type) GetProcAddress(library, "grpc_tls_credentials_options_set_cert_request_type");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 1079e42..0224b94 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -461,6 +461,9 @@
 typedef grpc_tls_certificate_provider*(*grpc_tls_certificate_provider_static_data_create_type)(const char* root_certificate, grpc_tls_identity_pairs* pem_key_cert_pairs);
 extern grpc_tls_certificate_provider_static_data_create_type grpc_tls_certificate_provider_static_data_create_import;
 #define grpc_tls_certificate_provider_static_data_create grpc_tls_certificate_provider_static_data_create_import
+typedef grpc_tls_certificate_provider*(*grpc_tls_certificate_provider_file_watcher_create_type)(const char* private_key_path, const char* identity_certificate_path, const char* root_cert_path, unsigned int refresh_interval_sec);
+extern grpc_tls_certificate_provider_file_watcher_create_type grpc_tls_certificate_provider_file_watcher_create_import;
+#define grpc_tls_certificate_provider_file_watcher_create grpc_tls_certificate_provider_file_watcher_create_import
 typedef void(*grpc_tls_certificate_provider_release_type)(grpc_tls_certificate_provider* provider);
 extern grpc_tls_certificate_provider_release_type grpc_tls_certificate_provider_release_import;
 #define grpc_tls_certificate_provider_release grpc_tls_certificate_provider_release_import
diff --git a/test/core/end2end/fixtures/h2_tls.cc b/test/core/end2end/fixtures/h2_tls.cc
index 4689cee..9157e1e 100644
--- a/test/core/end2end/fixtures/h2_tls.cc
+++ b/test/core/end2end/fixtures/h2_tls.cc
@@ -39,6 +39,7 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+// For normal TLS connections.
 #define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
 #define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
 #define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
@@ -60,7 +61,7 @@
   grpc_tls_certificate_provider* server_provider = nullptr;
 };
 
-static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
+static grpc_end2end_test_fixture chttp2_create_fixture_static_data(
     grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
     grpc_tls_version tls_version) {
   grpc_end2end_test_fixture f;
@@ -101,16 +102,47 @@
   return f;
 }
 
-static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_2(
-    grpc_channel_args* client_args, grpc_channel_args* server_args) {
-  return chttp2_create_fixture_secure_fullstack(client_args, server_args,
-                                                grpc_tls_version::TLS1_2);
+static grpc_end2end_test_fixture chttp2_create_fixture_cert_watcher(
+    grpc_channel_args* /*client_args*/, grpc_channel_args* /*server_args*/,
+    grpc_tls_version tls_version) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  fullstack_secure_fixture_data* ffd = new fullstack_secure_fixture_data();
+  memset(&f, 0, sizeof(f));
+  ffd->localaddr = grpc_core::JoinHostPort("localhost", port);
+  ffd->tls_version = tls_version;
+  ffd->client_provider = grpc_tls_certificate_provider_file_watcher_create(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
+  ffd->server_provider = grpc_tls_certificate_provider_file_watcher_create(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
+  f.fixture_data = ffd;
+  f.cq = grpc_completion_queue_create_for_next(nullptr);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
+  return f;
 }
 
-static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack_tls1_3(
+static grpc_end2end_test_fixture chttp2_create_fixture_static_data_tls1_2(
     grpc_channel_args* client_args, grpc_channel_args* server_args) {
-  return chttp2_create_fixture_secure_fullstack(client_args, server_args,
-                                                grpc_tls_version::TLS1_3);
+  return chttp2_create_fixture_static_data(client_args, server_args,
+                                           grpc_tls_version::TLS1_2);
+}
+
+static grpc_end2end_test_fixture chttp2_create_fixture_static_data_tls1_3(
+    grpc_channel_args* client_args, grpc_channel_args* server_args) {
+  return chttp2_create_fixture_static_data(client_args, server_args,
+                                           grpc_tls_version::TLS1_3);
+}
+
+static grpc_end2end_test_fixture chttp2_create_fixture_cert_watcher_tls1_2(
+    grpc_channel_args* client_args, grpc_channel_args* server_args) {
+  return chttp2_create_fixture_cert_watcher(client_args, server_args,
+                                            grpc_tls_version::TLS1_2);
+}
+
+static grpc_end2end_test_fixture chttp2_create_fixture_cert_watcher_tls1_3(
+    grpc_channel_args* client_args, grpc_channel_args* server_args) {
+  return chttp2_create_fixture_cert_watcher(client_args, server_args,
+                                            grpc_tls_version::TLS1_3);
 }
 
 static void process_auth_failure(void* state, grpc_auth_context* /*ctx*/,
@@ -262,21 +294,47 @@
 }
 
 static grpc_end2end_test_config configs[] = {
-    /* client sync reload async authz + server sync reload. */
+    // client: static data provider + async custom verification
+    // server: static data provider
+    // extra: TLS 1.2
     {"chttp2/simple_ssl_fullstack_tls1_2",
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
          FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
          FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
          FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
-     "foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_2,
+     "foo.test.google.fr", chttp2_create_fixture_static_data_tls1_2,
      chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
+    // client: static data provider + async custom verification
+    // server: static data provider
+    // extra: TLS 1.3
     {"chttp2/simple_ssl_fullstack_tls1_3",
      FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
          FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
          FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
          FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
-     "foo.test.google.fr", chttp2_create_fixture_secure_fullstack_tls1_3,
+     "foo.test.google.fr", chttp2_create_fixture_static_data_tls1_3,
      chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
+    // client: certificate watcher provider + async custom verification
+    // server: certificate watcher provider
+    // extra: TLS 1.2
+    {"chttp2/reloading_from_files_ssl_fullstack_tls1_2",
+     FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
+         FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
+     "foo.test.google.fr", chttp2_create_fixture_cert_watcher_tls1_2,
+     chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
+    // client: certificate watcher provider + async custom verification
+    // server: certificate watcher provider
+    // extra: TLS 1.3
+    {"chttp2/reloading_from_files_ssl_fullstack_tls1_3",
+     FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
+         FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS |
+         FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+         FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER,
+     "foo.test.google.fr", chttp2_create_fixture_cert_watcher_tls1_3,
+     chttp2_init_client, chttp2_init_server, chttp2_tear_down_secure_fullstack},
+
 };
 
 int main(int argc, char** argv) {
diff --git a/test/core/security/BUILD b/test/core/security/BUILD
index e576028..31b77a2 100644
--- a/test/core/security/BUILD
+++ b/test/core/security/BUILD
@@ -287,6 +287,15 @@
     ],
 )
 
+grpc_cc_library(
+    name = "tls_utils",
+    srcs = ["tls_utils.cc"],
+    hdrs = ["tls_utils.h"],
+    language = "C++",
+    visibility = ["//test/cpp:__subpackages__"],
+    deps = ["//:grpc"],
+)
+
 grpc_cc_test(
     name = "tls_security_connector_test",
     srcs = ["tls_security_connector_test.cc"],
@@ -318,12 +327,17 @@
     srcs = ["grpc_tls_credentials_options_test.cc"],
     data = [
         "//src/core/tsi/test_creds:ca.pem",
+        "//src/core/tsi/test_creds:multi-domain.key",
+        "//src/core/tsi/test_creds:multi-domain.pem",
+        "//src/core/tsi/test_creds:server0.key",
+        "//src/core/tsi/test_creds:server0.pem",
         "//src/core/tsi/test_creds:server1.key",
         "//src/core/tsi/test_creds:server1.pem",
     ],
     external_deps = ["gtest"],
     language = "C++",
     deps = [
+        ":tls_utils",
         "//:gpr",
         "//:grpc",
         "//:grpc_secure",
@@ -337,6 +351,30 @@
     external_deps = ["gtest"],
     language = "C++",
     deps = [
+        ":tls_utils",
+        "//:gpr",
+        "//:grpc",
+        "//:grpc_secure",
+        "//test/core/util:grpc_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "grpc_tls_certificate_provider_test",
+    srcs = ["grpc_tls_certificate_provider_test.cc"],
+    data = [
+        "//src/core/tsi/test_creds:ca.pem",
+        "//src/core/tsi/test_creds:multi-domain.key",
+        "//src/core/tsi/test_creds:multi-domain.pem",
+        "//src/core/tsi/test_creds:server0.key",
+        "//src/core/tsi/test_creds:server0.pem",
+        "//src/core/tsi/test_creds:server1.key",
+        "//src/core/tsi/test_creds:server1.pem",
+    ],
+    external_deps = ["gtest"],
+    language = "C++",
+    deps = [
+        ":tls_utils",
         "//:gpr",
         "//:grpc",
         "//:grpc_secure",
diff --git a/test/core/security/grpc_tls_certificate_distributor_test.cc b/test/core/security/grpc_tls_certificate_distributor_test.cc
index 61be71c..b8dfaa1 100644
--- a/test/core/security/grpc_tls_certificate_distributor_test.cc
+++ b/test/core/security/grpc_tls_certificate_distributor_test.cc
@@ -28,8 +28,11 @@
 #include <thread>
 
 #include "src/core/lib/slice/slice_internal.h"
+#include "test/core/security/tls_utils.h"
 #include "test/core/util/test_config.h"
 
+namespace grpc_core {
+
 namespace testing {
 
 constexpr const char* kCertName1 = "cert_1_name";
@@ -53,29 +56,14 @@
   // Forward declaration.
   class TlsCertificatesTestWatcher;
 
-  static grpc_core::PemKeyCertPairList MakeCertKeyPairs(const char* private_key,
-                                                        const char* certs) {
-    if (strcmp(private_key, "") == 0 && strcmp(certs, "") == 0) {
-      return {};
-    }
-    grpc_ssl_pem_key_cert_pair* ssl_pair =
-        static_cast<grpc_ssl_pem_key_cert_pair*>(
-            gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
-    ssl_pair->private_key = gpr_strdup(private_key);
-    ssl_pair->cert_chain = gpr_strdup(certs);
-    grpc_core::PemKeyCertPairList pem_key_cert_pairs;
-    pem_key_cert_pairs.emplace_back(ssl_pair);
-    return pem_key_cert_pairs;
-  }
-
   // CredentialInfo contains the parameters when calling OnCertificatesChanged
   // of a watcher. When OnCertificatesChanged is invoked, we will push a
   // CredentialInfo to the cert_update_queue of state_, and check in each test
   // if the status updates are correct.
   struct CredentialInfo {
     std::string root_certs;
-    grpc_core::PemKeyCertPairList key_cert_pairs;
-    CredentialInfo(std::string root, grpc_core::PemKeyCertPairList key_cert)
+    PemKeyCertPairList key_cert_pairs;
+    CredentialInfo(std::string root, PemKeyCertPairList key_cert)
         : root_certs(std::move(root)), key_cert_pairs(std::move(key_cert)) {}
     bool operator==(const CredentialInfo& other) const {
       return root_certs == other.root_certs &&
@@ -128,12 +116,12 @@
 
     void OnCertificatesChanged(
         absl::optional<absl::string_view> root_certs,
-        absl::optional<grpc_core::PemKeyCertPairList> key_cert_pairs) override {
+        absl::optional<PemKeyCertPairList> key_cert_pairs) override {
       std::string updated_root;
       if (root_certs.has_value()) {
         updated_root = std::string(*root_certs);
       }
-      grpc_core::PemKeyCertPairList updated_identity;
+      PemKeyCertPairList updated_identity;
       if (key_cert_pairs.has_value()) {
         updated_identity = std::move(*key_cert_pairs);
       }
@@ -151,8 +139,7 @@
         grpc_slice root_error_slice;
         GPR_ASSERT(grpc_error_get_str(
             root_cert_error, GRPC_ERROR_STR_DESCRIPTION, &root_error_slice));
-        root_error_str =
-            std::string(grpc_core::StringViewFromSlice(root_error_slice));
+        root_error_str = std::string(StringViewFromSlice(root_error_slice));
       }
       if (identity_cert_error != GRPC_ERROR_NONE) {
         grpc_slice identity_error_slice;
@@ -160,7 +147,7 @@
                                       GRPC_ERROR_STR_DESCRIPTION,
                                       &identity_error_slice));
         identity_error_str =
-            std::string(grpc_core::StringViewFromSlice(identity_error_slice));
+            std::string(StringViewFromSlice(identity_error_slice));
       }
       state_->error_queue.emplace_back(std::move(root_error_str),
                                        std::move(identity_error_str));
@@ -202,7 +189,7 @@
 
   WatcherState* MakeWatcher(absl::optional<std::string> root_cert_name,
                             absl::optional<std::string> identity_cert_name) {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     watchers_.emplace_back();
     // TlsCertificatesTestWatcher ctor takes a pointer to the WatcherState.
     // It sets WatcherState::watcher to point to itself.
@@ -217,7 +204,7 @@
   }
 
   void CancelWatch(WatcherState* state) {
-    grpc_core::MutexLock lock(&mu_);
+    MutexLock lock(&mu_);
     distributor_.CancelTlsCertificatesWatch(state->watcher);
     EXPECT_EQ(state->watcher, nullptr);
   }
@@ -234,7 +221,7 @@
   std::list<WatcherState> watchers_;
   std::deque<CallbackStatus> callback_queue_;
   // This is to make watchers_ and callback_queue_ thread-safe.
-  grpc_core::Mutex mu_;
+  Mutex mu_;
 };
 
 TEST_F(GrpcTlsCertificateDistributorTest, BasicCredentialBehaviors) {
@@ -257,21 +244,21 @@
 TEST_F(GrpcTlsCertificateDistributorTest, UpdateCredentialsOnAnySide) {
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   // SetKeyMaterials should trigger watcher's OnCertificatesChanged method.
   distributor_.SetKeyMaterials(
       kCertName1, kRootCert1Contents,
       MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   // Set root certs should trigger watcher's OnCertificatesChanged again.
   distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert2Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   // Set identity certs should trigger watcher's OnCertificatesChanged again.
@@ -280,7 +267,7 @@
       MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert2Contents,
           MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
   CancelWatch(watcher_state_1);
@@ -292,12 +279,12 @@
       MakeWatcher(kRootCert1Name, kIdentityCert1Name);
   EXPECT_THAT(
       GetCallbackQueue(),
-      testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
-                           CallbackStatus(kIdentityCert1Name, false, true)));
+      ::testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
+                             CallbackStatus(kIdentityCert1Name, false, true)));
   // Register watcher 2.
   WatcherState* watcher_state_2 =
       MakeWatcher(kRootCert2Name, kIdentityCert1Name);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
                                       kRootCert2Name, true, false)));
   // Push credential updates to kRootCert1Name and check if the status works as
   // expected.
@@ -305,13 +292,13 @@
                                absl::nullopt);
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
   // Push credential updates to kRootCert2Name.
   distributor_.SetKeyMaterials(kRootCert2Name, kRootCert2Contents,
                                absl::nullopt);
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
   // Push credential updates to kIdentityCert1Name and check if the status works
   // as expected.
   distributor_.SetKeyMaterials(
@@ -320,24 +307,24 @@
   // Check the updates are delivered to watcher 1 and watcher 2.
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   EXPECT_THAT(
       watcher_state_2->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert2Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   // Cancel watcher 1.
   CancelWatch(watcher_state_1);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
                                       kRootCert1Name, false, false)));
   // Cancel watcher 2.
   CancelWatch(watcher_state_2);
   EXPECT_THAT(
       GetCallbackQueue(),
-      testing::ElementsAre(CallbackStatus(kRootCert2Name, false, false),
-                           CallbackStatus(kIdentityCert1Name, false, false)));
+      ::testing::ElementsAre(CallbackStatus(kRootCert2Name, false, false),
+                             CallbackStatus(kIdentityCert1Name, false, false)));
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest, SameRootNameDiffIdentityName) {
@@ -346,12 +333,12 @@
       MakeWatcher(kRootCert1Name, kIdentityCert1Name);
   EXPECT_THAT(
       GetCallbackQueue(),
-      testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
-                           CallbackStatus(kIdentityCert1Name, false, true)));
+      ::testing::ElementsAre(CallbackStatus(kRootCert1Name, true, false),
+                             CallbackStatus(kIdentityCert1Name, false, true)));
   // Register watcher 2.
   WatcherState* watcher_state_2 =
       MakeWatcher(kRootCert1Name, kIdentityCert2Name);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
                                       kIdentityCert2Name, false, true)));
   // Push credential updates to kRootCert1Name and check if the status works as
   // expected.
@@ -359,10 +346,10 @@
                                absl::nullopt);
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
   // Push credential updates to SetKeyMaterials.
   distributor_.SetKeyMaterials(
       kIdentityCert1Name, absl::nullopt,
@@ -370,7 +357,7 @@
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   // Push credential updates to kIdentityCert2Name.
@@ -380,19 +367,19 @@
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(
       watcher_state_2->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
   // Cancel watcher 1.
   CancelWatch(watcher_state_1);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre(CallbackStatus(
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre(CallbackStatus(
                                       kIdentityCert1Name, false, false)));
   // Cancel watcher 2.
   CancelWatch(watcher_state_2);
   EXPECT_THAT(
       GetCallbackQueue(),
-      testing::ElementsAre(CallbackStatus(kRootCert1Name, false, false),
-                           CallbackStatus(kIdentityCert2Name, false, false)));
+      ::testing::ElementsAre(CallbackStatus(kRootCert1Name, false, false),
+                             CallbackStatus(kIdentityCert2Name, false, false)));
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest,
@@ -400,7 +387,7 @@
   // Register watcher 1 watching kCertName1 for both root and identity certs.
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   // Push credential updates to kCertName1 and check if the status works as
   // expected.
   distributor_.SetKeyMaterials(
@@ -409,13 +396,13 @@
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   // Cancel watcher 1.
   CancelWatch(watcher_state_1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest,
@@ -423,11 +410,11 @@
   // Register watcher 1 watching kCertName1 for root certs.
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, absl::nullopt);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
   // Register watcher 2 watching kCertName1 for identity certs.
   WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   // Push credential updates to kCertName1 and check if the status works as
   // expected.
   distributor_.SetKeyMaterials(
@@ -435,39 +422,39 @@
       MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(
+              ::testing::ElementsAre(CredentialInfo(
                   "", MakeCertKeyPairs(kIdentityCert1PrivateKey,
                                        kIdentityCert1Contents))));
   // Push root cert updates to kCertName1.
   distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
   // Check the updates are not delivered to watcher 2.
-  EXPECT_THAT(watcher_state_2->GetCredentialQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_2->GetCredentialQueue(), ::testing::ElementsAre());
   // Push identity cert updates to kCertName1.
   distributor_.SetKeyMaterials(
       kCertName1, absl::nullopt,
       MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
   // Check the updates are not delivered to watcher 1.
-  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(
+              ::testing::ElementsAre(CredentialInfo(
                   "", MakeCertKeyPairs(kIdentityCert2PrivateKey,
                                        kIdentityCert2Contents))));
   watcher_state_2->cert_update_queue.clear();
   // Cancel watcher 2.
   CancelWatch(watcher_state_2);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, false)));
   // Cancel watcher 1.
   CancelWatch(watcher_state_1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest,
@@ -475,11 +462,11 @@
   // Register watcher 1 watching kCertName1 for identity certs.
   WatcherState* watcher_state_1 = MakeWatcher(absl::nullopt, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
   // Register watcher 2 watching kCertName1 for root certs.
   WatcherState* watcher_state_2 = MakeWatcher(kCertName1, absl::nullopt);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   // Push credential updates to kCertName1 and check if the status works as
   // expected.
   distributor_.SetKeyMaterials(
@@ -487,38 +474,38 @@
       MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(
+              ::testing::ElementsAre(CredentialInfo(
                   "", MakeCertKeyPairs(kIdentityCert1PrivateKey,
                                        kIdentityCert1Contents))));
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert1Contents, {})));
   // Push root cert updates to kCertName1.
   distributor_.SetKeyMaterials(kCertName1, kRootCert2Contents, absl::nullopt);
   // Check the updates are delivered to watcher 2.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
   // Check the updates are not delivered to watcher 1.
-  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
   // Push identity cert updates to kCertName1.
   distributor_.SetKeyMaterials(
       kCertName1, absl::nullopt,
       MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents));
   // Check the updates are not delivered to watcher 2.
-  EXPECT_THAT(watcher_state_2->GetCredentialQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_2->GetCredentialQueue(), ::testing::ElementsAre());
   // Check the updates are delivered to watcher 1.
   EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(
+              ::testing::ElementsAre(CredentialInfo(
                   "", MakeCertKeyPairs(kIdentityCert2PrivateKey,
                                        kIdentityCert2Contents))));
   // Cancel watcher 2.
   CancelWatch(watcher_state_2);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, true)));
   // Cancel watcher 1.
   CancelWatch(watcher_state_1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest,
@@ -527,24 +514,24 @@
   // certs.
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   WatcherState* watcher_state_2 = MakeWatcher(kCertName1, kCertName1);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre());
   // Push credential updates to kCertName1.
   distributor_.SetKeyMaterials(
       kCertName1, kRootCert1Contents,
       MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents));
   // Cancel watcher 2.
   CancelWatch(watcher_state_2);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre());
   // Cancel watcher 1.
   CancelWatch(watcher_state_1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
   // Register watcher 3 watching kCertName for root and identity certs.
   WatcherState* watcher_state_3 = MakeWatcher(kCertName1, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   // Push credential updates to kCertName1.
   distributor_.SetKeyMaterials(
       kCertName1, kRootCert2Contents,
@@ -552,25 +539,25 @@
   // Check the updates are delivered to watcher 3.
   EXPECT_THAT(
       watcher_state_3->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert2Contents,
           MakeCertKeyPairs(kIdentityCert2PrivateKey, kIdentityCert2Contents))));
   // Cancel watcher 3.
   CancelWatch(watcher_state_3);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, false, false)));
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest, ResetCallbackToNull) {
   // Register watcher 1 watching kCertName1 for root and identity certs.
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName1);
   EXPECT_THAT(GetCallbackQueue(),
-              testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
+              ::testing::ElementsAre(CallbackStatus(kCertName1, true, true)));
   // Reset callback to nullptr.
   distributor_.SetWatchStatusCallback(nullptr);
   // Cancel watcher 1 shouldn't trigger any callback.
   CancelWatch(watcher_state_1);
-  EXPECT_THAT(GetCallbackQueue(), testing::ElementsAre());
+  EXPECT_THAT(GetCallbackQueue(), ::testing::ElementsAre());
 }
 
 TEST_F(GrpcTlsCertificateDistributorTest, SetKeyMaterialsInCallback) {
@@ -586,7 +573,7 @@
     // Check the updates are delivered to watcher 1.
     EXPECT_THAT(
         watcher_state_1->GetCredentialQueue(),
-        testing::ElementsAre(CredentialInfo(
+        ::testing::ElementsAre(CredentialInfo(
             kRootCert1Contents, MakeCertKeyPairs(kIdentityCert1PrivateKey,
                                                  kIdentityCert1Contents))));
     CancelWatch(watcher_state_1);
@@ -621,7 +608,7 @@
   // watcher 1 should receive the credentials right away.
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   CancelWatch(watcher_state_1);
@@ -629,13 +616,13 @@
   WatcherState* watcher_state_2 = MakeWatcher(kRootCert2Name, absl::nullopt);
   // watcher 2 should receive the root credentials right away.
   EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
+              ::testing::ElementsAre(CredentialInfo(kRootCert2Contents, {})));
   // Register watcher 3.
   WatcherState* watcher_state_3 =
       MakeWatcher(absl::nullopt, kIdentityCert2Name);
   // watcher 3 should received the identity credentials right away.
   EXPECT_THAT(watcher_state_3->GetCredentialQueue(),
-              testing::ElementsAre(CredentialInfo(
+              ::testing::ElementsAre(CredentialInfo(
                   "", MakeCertKeyPairs(kIdentityCert2PrivateKey,
                                        kIdentityCert2Contents))));
   CancelWatch(watcher_state_2);
@@ -652,7 +639,7 @@
       kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(
+              ::testing::ElementsAre(
                   ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
   // Calling SetErrorForCert on root cert name should call OnError
   // on watcher 1 again.
@@ -661,14 +648,14 @@
       absl::nullopt);
   EXPECT_THAT(
       watcher_state_1->GetErrorQueue(),
-      testing::ElementsAre(ErrorInfo(kErrorMessage, kIdentityErrorMessage)));
+      ::testing::ElementsAre(ErrorInfo(kErrorMessage, kIdentityErrorMessage)));
   // Calling SetErrorForCert on identity cert name should call OnError
   // on watcher 1 again.
   distributor_.SetErrorForCert(
       kCertName1, absl::nullopt,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
   distributor_.CancelTlsCertificatesWatch(watcher_state_1->watcher);
   EXPECT_EQ(watcher_state_1->watcher, nullptr);
 }
@@ -682,18 +669,18 @@
       kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       absl::nullopt);
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
+              ::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
   // Calling SetErrorForCert on identity name should do nothing.
   distributor_.SetErrorForCert(
       kCertName1, absl::nullopt,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
-  EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
   // Calling SetErrorForCert on both names should still get one OnError call.
   distributor_.SetErrorForCert(
       kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
+              ::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
   CancelWatch(watcher_state_1);
   // Register watcher 2.
   WatcherState* watcher_state_2 = MakeWatcher(absl::nullopt, kCertName1);
@@ -703,18 +690,18 @@
       kCertName1, absl::nullopt,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_2->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
   // Calling SetErrorForCert on root name should do nothing.
   distributor_.SetErrorForCert(
       kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       absl::nullopt);
-  EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
   // Calling SetErrorForCert on both names should still get one OnError call.
   distributor_.SetErrorForCert(
       kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_2->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
   CancelWatch(watcher_state_2);
 }
 
@@ -728,14 +715,14 @@
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName2);
   // Should trigger OnError call right away since kCertName1 has error.
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
+              ::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
   // Calling SetErrorForCert on kCertName2 should trigger OnError with both
   // errors, because kCertName1 also has error.
   distributor_.SetErrorForCert(
       kCertName2, absl::nullopt,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(
+              ::testing::ElementsAre(
                   ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
   CancelWatch(watcher_state_1);
 }
@@ -750,14 +737,14 @@
   WatcherState* watcher_state_1 = MakeWatcher(kCertName2, kCertName1);
   // Should trigger OnError call right away since kCertName2 has error.
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
   // Calling SetErrorForCert on kCertName2 should trigger OnError with both
   // errors, because kCertName1 also has error.
   distributor_.SetErrorForCert(
       kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       absl::nullopt);
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(
+              ::testing::ElementsAre(
                   ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
   CancelWatch(watcher_state_1);
 }
@@ -767,25 +754,25 @@
   // Register watcher 1 for kCertName1 as root and kCertName2 as identity.
   WatcherState* watcher_state_1 = MakeWatcher(kCertName1, kCertName2);
   // Should not trigger OnError.
-  EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
   // Calling SetErrorForCert on kCertName2 should trigger OnError.
   distributor_.SetErrorForCert(
       kCertName2, absl::nullopt,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
   CancelWatch(watcher_state_1);
   // Register watcher 2 for kCertName2 as identity and a non-existing name
   // kRootCert1Name as root.
   WatcherState* watcher_state_2 = MakeWatcher(kRootCert1Name, kCertName2);
   // Should not trigger OnError.
-  EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
   // Calling SetErrorForCert on kCertName2 should trigger OnError.
   distributor_.SetErrorForCert(
       kCertName2, absl::nullopt,
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_2->error_queue,
-              testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo("", kIdentityErrorMessage)));
   CancelWatch(watcher_state_2);
 }
 
@@ -793,25 +780,25 @@
        SetErrorForRootNameWithPreexistingErrorForIdentityName) {
   WatcherState* watcher_state_1 = MakeWatcher(kCertName2, kCertName1);
   // Should not trigger OnError.
-  EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
   // Calling SetErrorForCert on kCertName2 should trigger OnError.
   distributor_.SetErrorForCert(
       kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       absl::nullopt);
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
+              ::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
   CancelWatch(watcher_state_1);
   // Register watcher 2 for kCertName2 as root and a non-existing name
   // kIdentityCert1Name as identity.
   WatcherState* watcher_state_2 = MakeWatcher(kCertName2, kIdentityCert1Name);
   // Should not trigger OnError.
-  EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
   // Calling SetErrorForCert on kCertName2 should trigger OnError.
   distributor_.SetErrorForCert(
       kCertName2, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       absl::nullopt);
   EXPECT_THAT(watcher_state_2->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
+              ::testing::ElementsAre(ErrorInfo(kRootErrorMessage, "")));
   CancelWatch(watcher_state_2);
 }
 
@@ -825,14 +812,14 @@
       kCertName1, GRPC_ERROR_CREATE_FROM_STATIC_STRING(kRootErrorMessage),
       GRPC_ERROR_CREATE_FROM_STATIC_STRING(kIdentityErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(
+              ::testing::ElementsAre(
                   ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
   // When watcher 1 is removed, the cert info entry should be removed.
   CancelWatch(watcher_state_1);
   // Register watcher 2 on the same cert name.
   WatcherState* watcher_state_2 = MakeWatcher(kCertName1, kCertName1);
   // Should not trigger OnError call on watcher 2 right away.
-  EXPECT_THAT(watcher_state_2->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_2->GetErrorQueue(), ::testing::ElementsAre());
   CancelWatch(watcher_state_2);
 }
 
@@ -851,11 +838,11 @@
   // watcher 1 should receive both the old credentials and the error right away.
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(
+              ::testing::ElementsAre(
                   ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
   CancelWatch(watcher_state_1);
 }
@@ -876,10 +863,10 @@
   // the previous error is wiped out by a successful update.
   EXPECT_THAT(
       watcher_state_1->GetCredentialQueue(),
-      testing::ElementsAre(CredentialInfo(
+      ::testing::ElementsAre(CredentialInfo(
           kRootCert1Contents,
           MakeCertKeyPairs(kIdentityCert1PrivateKey, kIdentityCert1Contents))));
-  EXPECT_THAT(watcher_state_1->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(), ::testing::ElementsAre());
   CancelWatch(watcher_state_1);
 }
 
@@ -893,11 +880,11 @@
       MakeWatcher(absl::nullopt, kIdentityCert1Name);
   distributor_.SetError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(kErrorMessage));
   EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo(kErrorMessage, kErrorMessage)));
   EXPECT_THAT(watcher_state_2->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo(kErrorMessage, "")));
+              ::testing::ElementsAre(ErrorInfo(kErrorMessage, "")));
   EXPECT_THAT(watcher_state_3->GetErrorQueue(),
-              testing::ElementsAre(ErrorInfo("", kErrorMessage)));
+              ::testing::ElementsAre(ErrorInfo("", kErrorMessage)));
   CancelWatch(watcher_state_1);
   CancelWatch(watcher_state_2);
   CancelWatch(watcher_state_3);
@@ -915,12 +902,12 @@
   // Register watcher 3 watching kCertName1 as root and kCertName2 as identity
   // should not get the error updates.
   WatcherState* watcher_state_3 = MakeWatcher(kCertName1, kCertName2);
-  EXPECT_THAT(watcher_state_3->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_3->GetErrorQueue(), ::testing::ElementsAre());
   CancelWatch(watcher_state_3);
   // Register watcher 4 watching kCertName2 as root and kCertName1 as identity
   // should not get the error updates.
   WatcherState* watcher_state_4 = MakeWatcher(kCertName2, kCertName1);
-  EXPECT_THAT(watcher_state_4->GetErrorQueue(), testing::ElementsAre());
+  EXPECT_THAT(watcher_state_4->GetErrorQueue(), ::testing::ElementsAre());
   CancelWatch(watcher_state_4);
 }
 
@@ -936,7 +923,7 @@
     WatcherState* watcher_state_1 = MakeWatcher(cert_name, cert_name);
     // Check the errors are delivered to watcher 1.
     EXPECT_THAT(watcher_state_1->GetErrorQueue(),
-                testing::ElementsAre(
+                ::testing::ElementsAre(
                     ErrorInfo(kRootErrorMessage, kIdentityErrorMessage)));
     CancelWatch(watcher_state_1);
   };
@@ -955,6 +942,8 @@
 
 }  // namespace testing
 
+}  // namespace grpc_core
+
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/test/core/security/grpc_tls_certificate_provider_test.cc b/test/core/security/grpc_tls_certificate_provider_test.cc
new file mode 100644
index 0000000..b8bebf7
--- /dev/null
+++ b/test/core/security/grpc_tls_certificate_provider_test.cc
@@ -0,0 +1,509 @@
+//
+// Copyright 2020 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
+
+#include <gmock/gmock.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <gtest/gtest.h>
+
+#include <deque>
+#include <list>
+
+#include "src/core/lib/gpr/tmpfile.h"
+#include "src/core/lib/iomgr/load_file.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "test/core/security/tls_utils.h"
+#include "test/core/util/test_config.h"
+
+#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
+#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
+#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
+#define CA_CERT_PATH_2 "src/core/tsi/test_creds/multi-domain.pem"
+#define SERVER_CERT_PATH_2 "src/core/tsi/test_creds/server0.pem"
+#define SERVER_KEY_PATH_2 "src/core/tsi/test_creds/server0.key"
+#define INVALID_PATH "invalid/path"
+
+namespace grpc_core {
+
+namespace testing {
+
+constexpr const char* kCertName = "cert_name";
+constexpr const char* kRootError = "Unable to get latest root certificates.";
+constexpr const char* kIdentityError =
+    "Unable to get latest identity certificates.";
+
+class GrpcTlsCertificateProviderTest : public ::testing::Test {
+ protected:
+  // Forward declaration.
+  class TlsCertificatesTestWatcher;
+
+  // CredentialInfo contains the parameters when calling OnCertificatesChanged
+  // of a watcher. When OnCertificatesChanged is invoked, we will push a
+  // CredentialInfo to the cert_update_queue of state_, and check in each test
+  // if the status updates are correct.
+  struct CredentialInfo {
+    std::string root_certs;
+    PemKeyCertPairList key_cert_pairs;
+    CredentialInfo(std::string root, PemKeyCertPairList key_cert)
+        : root_certs(std::move(root)), key_cert_pairs(std::move(key_cert)) {}
+    bool operator==(const CredentialInfo& other) const {
+      return root_certs == other.root_certs &&
+             key_cert_pairs == other.key_cert_pairs;
+    }
+  };
+
+  // ErrorInfo contains the parameters when calling OnError of a watcher. When
+  // OnError is invoked, we will push a ErrorInfo to the error_queue of state_,
+  // and check in each test if the status updates are correct.
+  struct ErrorInfo {
+    std::string root_cert_str;
+    std::string identity_cert_str;
+    ErrorInfo(std::string root, std::string identity)
+        : root_cert_str(std::move(root)),
+          identity_cert_str(std::move(identity)) {}
+    bool operator==(const ErrorInfo& other) const {
+      return root_cert_str == other.root_cert_str &&
+             identity_cert_str == other.identity_cert_str;
+    }
+  };
+
+  struct WatcherState {
+    TlsCertificatesTestWatcher* watcher = nullptr;
+    std::deque<CredentialInfo> cert_update_queue;
+    std::deque<ErrorInfo> error_queue;
+    Mutex mu;
+
+    std::deque<CredentialInfo> GetCredentialQueue() {
+      // We move the data member value so the data member will be re-initiated
+      // with size 0, and ready for the next check.
+      MutexLock lock(&mu);
+      return std::move(cert_update_queue);
+    }
+    std::deque<ErrorInfo> GetErrorQueue() {
+      // We move the data member value so the data member will be re-initiated
+      // with size 0, and ready for the next check.
+      MutexLock lock(&mu);
+      return std::move(error_queue);
+    }
+  };
+
+  class TlsCertificatesTestWatcher : public grpc_tls_certificate_distributor::
+                                         TlsCertificatesWatcherInterface {
+   public:
+    // ctor sets state->watcher to this.
+    explicit TlsCertificatesTestWatcher(WatcherState* state) : state_(state) {
+      state_->watcher = this;
+    }
+
+    // dtor sets state->watcher to nullptr.
+    ~TlsCertificatesTestWatcher() override { state_->watcher = nullptr; }
+
+    void OnCertificatesChanged(
+        absl::optional<absl::string_view> root_certs,
+        absl::optional<PemKeyCertPairList> key_cert_pairs) override {
+      MutexLock lock(&state_->mu);
+      std::string updated_root;
+      if (root_certs.has_value()) {
+        updated_root = std::string(*root_certs);
+      }
+      PemKeyCertPairList updated_identity;
+      if (key_cert_pairs.has_value()) {
+        updated_identity = std::move(*key_cert_pairs);
+      }
+      state_->cert_update_queue.emplace_back(std::move(updated_root),
+                                             std::move(updated_identity));
+    }
+
+    void OnError(grpc_error* root_cert_error,
+                 grpc_error* identity_cert_error) override {
+      MutexLock lock(&state_->mu);
+      GPR_ASSERT(root_cert_error != GRPC_ERROR_NONE ||
+                 identity_cert_error != GRPC_ERROR_NONE);
+      std::string root_error_str;
+      std::string identity_error_str;
+      if (root_cert_error != GRPC_ERROR_NONE) {
+        grpc_slice root_error_slice;
+        GPR_ASSERT(grpc_error_get_str(
+            root_cert_error, GRPC_ERROR_STR_DESCRIPTION, &root_error_slice));
+        root_error_str = std::string(StringViewFromSlice(root_error_slice));
+      }
+      if (identity_cert_error != GRPC_ERROR_NONE) {
+        grpc_slice identity_error_slice;
+        GPR_ASSERT(grpc_error_get_str(identity_cert_error,
+                                      GRPC_ERROR_STR_DESCRIPTION,
+                                      &identity_error_slice));
+        identity_error_str =
+            std::string(StringViewFromSlice(identity_error_slice));
+      }
+      state_->error_queue.emplace_back(std::move(root_error_str),
+                                       std::move(identity_error_str));
+      GRPC_ERROR_UNREF(root_cert_error);
+      GRPC_ERROR_UNREF(identity_cert_error);
+    }
+
+   private:
+    WatcherState* state_;
+  };
+
+  void SetUp() override {
+    root_cert_ = GetFileContents(CA_CERT_PATH);
+    cert_chain_ = GetFileContents(SERVER_CERT_PATH);
+    private_key_ = GetFileContents(SERVER_KEY_PATH);
+    root_cert_2_ = GetFileContents(CA_CERT_PATH_2);
+    cert_chain_2_ = GetFileContents(SERVER_CERT_PATH_2);
+    private_key_2_ = GetFileContents(SERVER_KEY_PATH_2);
+  }
+
+  WatcherState* MakeWatcher(
+      RefCountedPtr<grpc_tls_certificate_distributor> distributor,
+      absl::optional<std::string> root_cert_name,
+      absl::optional<std::string> identity_cert_name) {
+    MutexLock lock(&mu_);
+    distributor_ = distributor;
+    watchers_.emplace_back();
+    // TlsCertificatesTestWatcher ctor takes a pointer to the WatcherState.
+    // It sets WatcherState::watcher to point to itself.
+    // The TlsCertificatesTestWatcher dtor will set WatcherState::watcher back
+    // to nullptr to indicate that it's been destroyed.
+    auto watcher =
+        absl::make_unique<TlsCertificatesTestWatcher>(&watchers_.back());
+    distributor_->WatchTlsCertificates(std::move(watcher),
+                                       std::move(root_cert_name),
+                                       std::move(identity_cert_name));
+    return &watchers_.back();
+  }
+
+  void CancelWatch(WatcherState* state) {
+    MutexLock lock(&mu_);
+    distributor_->CancelTlsCertificatesWatch(state->watcher);
+    EXPECT_EQ(state->watcher, nullptr);
+  }
+
+  std::string root_cert_;
+  std::string private_key_;
+  std::string cert_chain_;
+  std::string root_cert_2_;
+  std::string private_key_2_;
+  std::string cert_chain_2_;
+  RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
+  // Use a std::list<> here to avoid the address invalidation caused by internal
+  // reallocation of std::vector<>.
+  std::list<WatcherState> watchers_;
+  // This is to make watchers_ thread-safe.
+  Mutex mu_;
+};
+
+TEST_F(GrpcTlsCertificateProviderTest, StaticDataCertificateProviderCreation) {
+  StaticDataCertificateProvider provider(
+      root_cert_, MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  // Watcher watching both root and identity certs.
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  CancelWatch(watcher_state_1);
+  // Watcher watching only root certs.
+  WatcherState* watcher_state_2 =
+      MakeWatcher(provider.distributor(), kCertName, absl::nullopt);
+  EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(root_cert_, {})));
+  CancelWatch(watcher_state_2);
+  // Watcher watching only identity certs.
+  WatcherState* watcher_state_3 =
+      MakeWatcher(provider.distributor(), absl::nullopt, kCertName);
+  EXPECT_THAT(
+      watcher_state_3->GetCredentialQueue(),
+      ::testing::ElementsAre(CredentialInfo(
+          "", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()))));
+  CancelWatch(watcher_state_3);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderWithGoodPaths) {
+  FileWatcherCertificateProvider provider(SERVER_KEY_PATH, SERVER_CERT_PATH,
+                                          CA_CERT_PATH, 1);
+  // Watcher watching both root and identity certs.
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  CancelWatch(watcher_state_1);
+  // Watcher watching only root certs.
+  WatcherState* watcher_state_2 =
+      MakeWatcher(provider.distributor(), kCertName, absl::nullopt);
+  EXPECT_THAT(watcher_state_2->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(root_cert_, {})));
+  CancelWatch(watcher_state_2);
+  // Watcher watching only identity certs.
+  WatcherState* watcher_state_3 =
+      MakeWatcher(provider.distributor(), absl::nullopt, kCertName);
+  EXPECT_THAT(
+      watcher_state_3->GetCredentialQueue(),
+      ::testing::ElementsAre(CredentialInfo(
+          "", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()))));
+  CancelWatch(watcher_state_3);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderWithBadPaths) {
+  FileWatcherCertificateProvider provider(INVALID_PATH, INVALID_PATH,
+                                          INVALID_PATH, 1);
+  // Watcher watching both root and identity certs.
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(),
+              ::testing::ElementsAre(ErrorInfo(kRootError, kIdentityError)));
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
+  CancelWatch(watcher_state_1);
+  // Watcher watching only root certs.
+  WatcherState* watcher_state_2 =
+      MakeWatcher(provider.distributor(), kCertName, absl::nullopt);
+  EXPECT_THAT(watcher_state_2->GetErrorQueue(),
+              ::testing::ElementsAre(ErrorInfo(kRootError, "")));
+  EXPECT_THAT(watcher_state_2->GetCredentialQueue(), ::testing::ElementsAre());
+  CancelWatch(watcher_state_2);
+  // Watcher watching only identity certs.
+  WatcherState* watcher_state_3 =
+      MakeWatcher(provider.distributor(), absl::nullopt, kCertName);
+  EXPECT_THAT(watcher_state_3->GetErrorQueue(),
+              ::testing::ElementsAre(ErrorInfo("", kIdentityError)));
+  EXPECT_THAT(watcher_state_3->GetCredentialQueue(), ::testing::ElementsAre());
+  CancelWatch(watcher_state_3);
+}
+
+// The following tests write credential data to temporary files to test the
+// transition behavior of the provider.
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderOnBothCertsRefreshed) {
+  // Create temporary files and copy cert data into them.
+  TmpFile tmp_root_cert(root_cert_);
+  TmpFile tmp_identity_key(private_key_);
+  TmpFile tmp_identity_cert(cert_chain_);
+  // Create FileWatcherCertificateProvider.
+  FileWatcherCertificateProvider provider(tmp_identity_key.name(),
+                                          tmp_identity_cert.name(),
+                                          tmp_root_cert.name(), 1);
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  // Expect to see the credential data.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  // Copy new data to files.
+  // TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
+  // update when the directory renaming is added in gpr.
+  tmp_root_cert.RewriteFile(root_cert_2_);
+  tmp_identity_key.RewriteFile(private_key_2_);
+  tmp_identity_cert.RewriteFile(cert_chain_2_);
+  // Wait 2 seconds for the provider's refresh thread to read the updated files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see the new credential data.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_2_, MakeCertKeyPairs(private_key_2_.c_str(),
+                                                 cert_chain_2_.c_str()))));
+  // Clean up.
+  CancelWatch(watcher_state_1);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderOnRootCertsRefreshed) {
+  // Create temporary files and copy cert data into them.
+  TmpFile tmp_root_cert(root_cert_);
+  TmpFile tmp_identity_key(private_key_);
+  TmpFile tmp_identity_cert(cert_chain_);
+  // Create FileWatcherCertificateProvider.
+  FileWatcherCertificateProvider provider(tmp_identity_key.name(),
+                                          tmp_identity_cert.name(),
+                                          tmp_root_cert.name(), 1);
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  // Expect to see the credential data.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  // Copy new data to files.
+  // TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
+  // update when the directory renaming is added in gpr.
+  tmp_root_cert.RewriteFile(root_cert_2_);
+  // Wait 2 seconds for the provider's refresh thread to read the updated files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see the new credential data.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_2_, MakeCertKeyPairs(private_key_.c_str(),
+                                                 cert_chain_.c_str()))));
+  // Clean up.
+  CancelWatch(watcher_state_1);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderOnIdentityCertsRefreshed) {
+  // Create temporary files and copy cert data into them.
+  TmpFile tmp_root_cert(root_cert_);
+  TmpFile tmp_identity_key(private_key_);
+  TmpFile tmp_identity_cert(cert_chain_);
+  // Create FileWatcherCertificateProvider.
+  FileWatcherCertificateProvider provider(tmp_identity_key.name(),
+                                          tmp_identity_cert.name(),
+                                          tmp_root_cert.name(), 1);
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  // Expect to see the credential data.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  // Copy new data to files.
+  // TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
+  // update when the directory renaming is added in gpr.
+  tmp_identity_key.RewriteFile(private_key_2_);
+  tmp_identity_cert.RewriteFile(cert_chain_2_);
+  // Wait 2 seconds for the provider's refresh thread to read the updated files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see the new credential data.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_2_.c_str(),
+                                               cert_chain_2_.c_str()))));
+  // Clean up.
+  CancelWatch(watcher_state_1);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderWithGoodAtFirstThenDeletedBothCerts) {
+  // Create temporary files and copy cert data into it.
+  auto tmp_root_cert = absl::make_unique<TmpFile>(root_cert_);
+  auto tmp_identity_key = absl::make_unique<TmpFile>(private_key_);
+  auto tmp_identity_cert = absl::make_unique<TmpFile>(cert_chain_);
+  // Create FileWatcherCertificateProvider.
+  FileWatcherCertificateProvider provider(tmp_identity_key->name(),
+                                          tmp_identity_cert->name(),
+                                          tmp_root_cert->name(), 1);
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  // The initial data is all good, so we expect to have successful credential
+  // updates.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  // Delete TmpFile objects, which will remove the corresponding files.
+  tmp_root_cert.reset();
+  tmp_identity_key.reset();
+  tmp_identity_cert.reset();
+  // Wait 2 seconds for the provider's refresh thread to read the deleted files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see errors sent to watchers, and no credential updates.
+  // We have no ideas on how many errors we will receive, so we only check once.
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(),
+              ::testing::Contains(ErrorInfo(kRootError, kIdentityError)));
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
+  // Clean up.
+  CancelWatch(watcher_state_1);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderWithGoodAtFirstThenDeletedRootCerts) {
+  // Create temporary files and copy cert data into it.
+  auto tmp_root_cert = absl::make_unique<TmpFile>(root_cert_);
+  TmpFile tmp_identity_key(private_key_);
+  TmpFile tmp_identity_cert(cert_chain_);
+  // Create FileWatcherCertificateProvider.
+  FileWatcherCertificateProvider provider(tmp_identity_key.name(),
+                                          tmp_identity_cert.name(),
+                                          tmp_root_cert->name(), 1);
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  // The initial data is all good, so we expect to have successful credential
+  // updates.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  // Delete root TmpFile object, which will remove the corresponding file.
+  tmp_root_cert.reset();
+  // Wait 2 seconds for the provider's refresh thread to read the deleted files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see errors sent to watchers, and no credential updates.
+  // We have no ideas on how many errors we will receive, so we only check once.
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(),
+              ::testing::Contains(ErrorInfo(kRootError, "")));
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
+  // Clean up.
+  CancelWatch(watcher_state_1);
+}
+
+TEST_F(GrpcTlsCertificateProviderTest,
+       FileWatcherCertificateProviderWithGoodAtFirstThenDeletedIdentityCerts) {
+  // Create temporary files and copy cert data into it.
+  TmpFile tmp_root_cert(root_cert_);
+  auto tmp_identity_key = absl::make_unique<TmpFile>(private_key_);
+  auto tmp_identity_cert = absl::make_unique<TmpFile>(cert_chain_);
+  // Create FileWatcherCertificateProvider.
+  FileWatcherCertificateProvider provider(tmp_identity_key->name(),
+                                          tmp_identity_cert->name(),
+                                          tmp_root_cert.name(), 1);
+  WatcherState* watcher_state_1 =
+      MakeWatcher(provider.distributor(), kCertName, kCertName);
+  // The initial data is all good, so we expect to have successful credential
+  // updates.
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(),
+              ::testing::ElementsAre(CredentialInfo(
+                  root_cert_, MakeCertKeyPairs(private_key_.c_str(),
+                                               cert_chain_.c_str()))));
+  // Delete identity TmpFile objects, which will remove the corresponding files.
+  tmp_identity_key.reset();
+  tmp_identity_cert.reset();
+  // Wait 2 seconds for the provider's refresh thread to read the deleted files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see errors sent to watchers, and no credential updates.
+  // We have no ideas on how many errors we will receive, so we only check once.
+  EXPECT_THAT(watcher_state_1->GetErrorQueue(),
+              ::testing::Contains(ErrorInfo("", kIdentityError)));
+  EXPECT_THAT(watcher_state_1->GetCredentialQueue(), ::testing::ElementsAre());
+  // Clean up.
+  CancelWatch(watcher_state_1);
+}
+
+}  // namespace testing
+
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  grpc::testing::TestEnvironment env(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_init();
+  int ret = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return ret;
+}
diff --git a/test/core/security/grpc_tls_credentials_options_test.cc b/test/core/security/grpc_tls_credentials_options_test.cc
index dee1d47..932b478 100644
--- a/test/core/security/grpc_tls_credentials_options_test.cc
+++ b/test/core/security/grpc_tls_credentials_options_test.cc
@@ -24,24 +24,440 @@
 #include <grpc/support/string_util.h>
 #include <gtest/gtest.h>
 
+#include "src/core/lib/gpr/tmpfile.h"
 #include "src/core/lib/iomgr/load_file.h"
+#include "src/core/lib/security/credentials/tls/tls_credentials.h"
+#include "src/core/lib/security/security_connector/tls/tls_security_connector.h"
+#include "test/core/security/tls_utils.h"
 #include "test/core/util/test_config.h"
 
 #define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
 #define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
 #define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
+#define CA_CERT_PATH_2 "src/core/tsi/test_creds/multi-domain.pem"
+#define SERVER_CERT_PATH_2 "src/core/tsi/test_creds/server0.pem"
+#define SERVER_KEY_PATH_2 "src/core/tsi/test_creds/server0.key"
+#define INVALID_PATH "invalid/path"
+
+namespace grpc_core {
 
 namespace testing {
 
-TEST(GrpcTlsCredentialsOptionsTest, ErrorDetails) {
+class GrpcTlsCredentialsOptionsTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    root_cert_ = GetFileContents(CA_CERT_PATH);
+    cert_chain_ = GetFileContents(SERVER_CERT_PATH);
+    private_key_ = GetFileContents(SERVER_KEY_PATH);
+    root_cert_2_ = GetFileContents(CA_CERT_PATH_2);
+    cert_chain_2_ = GetFileContents(SERVER_CERT_PATH_2);
+    private_key_2_ = GetFileContents(SERVER_KEY_PATH_2);
+  }
+
+  std::string root_cert_;
+  std::string private_key_;
+  std::string cert_chain_;
+  std::string root_cert_2_;
+  std::string private_key_2_;
+  std::string cert_chain_2_;
+};
+
+TEST_F(GrpcTlsCredentialsOptionsTest, ErrorDetails) {
   grpc_tls_error_details error_details;
   EXPECT_STREQ(error_details.error_details().c_str(), "");
   error_details.set_error_details("test error details");
   EXPECT_STREQ(error_details.error_details().c_str(), "test error details");
 }
 
+// Tests for StaticDataCertificateProvider.
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithStaticDataProviderOnBothCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      root_cert_, MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_watch_identity_pair(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithStaticDataProviderOnRootCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      root_cert_, PemKeyCertPairList());
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_FALSE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithStaticDataProviderOnNotProvidedCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      "", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_EQ(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithStaticDataProviderOnBothCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      root_cert_, MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(
+      GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+  EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithStaticDataProviderOnIdentityCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      "", MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+  EXPECT_FALSE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithStaticDataProviderOnNotProvidedCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<StaticDataCertificateProvider>(
+      root_cert_, PemKeyCertPairList());
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+}
+
+//// Tests for FileWatcherCertificateProvider.
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithCertWatcherProviderOnBothCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_watch_identity_pair(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithCertWatcherProviderOnRootCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider =
+      MakeRefCounted<FileWatcherCertificateProvider>("", "", CA_CERT_PATH, 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_FALSE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithCertWatcherProviderOnNotProvidedCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, "", 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_EQ(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithCertWatcherProviderOnBadTrustCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider =
+      MakeRefCounted<FileWatcherCertificateProvider>("", "", INVALID_PATH, 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  EXPECT_EQ(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithCertWatcherProviderOnBothCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(
+      GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+  EXPECT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithCertWatcherProviderOnIdentityCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, "", 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_NE(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+  EXPECT_FALSE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithCertWatcherProviderOnNotProvidedCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider =
+      MakeRefCounted<FileWatcherCertificateProvider>("", "", CA_CERT_PATH, 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ServerOptionsWithCertWatcherProviderOnBadIdentityCerts) {
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      INVALID_PATH, INVALID_PATH, "", 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_identity_pair(true);
+  options->set_cert_request_type(GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE);
+  auto credentials = MakeRefCounted<TlsServerCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  auto connector = credentials->create_security_connector();
+  ASSERT_NE(connector, nullptr);
+  TlsServerSecurityConnector* tls_connector =
+      static_cast<TlsServerSecurityConnector*>(connector.get());
+  EXPECT_EQ(tls_connector->ServerHandshakerFactoryForTesting(), nullptr);
+}
+
+// The following tests write credential data to temporary files to test the
+// transition behavior of the provider.
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithCertWatcherProviderOnCertificateRefreshed) {
+  // Create temporary files and copy cert data into them.
+  TmpFile tmp_root_cert(root_cert_);
+  TmpFile tmp_identity_key(private_key_);
+  TmpFile tmp_identity_cert(cert_chain_);
+  // Create ClientOptions using FileWatcherCertificateProvider.
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      tmp_identity_key.name(), tmp_identity_cert.name(), tmp_root_cert.name(),
+      1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_watch_identity_pair(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  // Expect to see the credential data.
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_);
+  ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+  EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
+            MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  // Copy new data to files.
+  // TODO(ZhenLian): right now it is not completely atomic. Use the real atomic
+  // update when the directory renaming is added in gpr.
+  tmp_root_cert.RewriteFile(root_cert_2_);
+  tmp_identity_key.RewriteFile(private_key_2_);
+  tmp_identity_cert.RewriteFile(cert_chain_2_);
+  // Wait 2 seconds for the provider's refresh thread to read the updated files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // Expect to see new credential data loaded by the security connector.
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_2_);
+  ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+  EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
+            MakeCertKeyPairs(private_key_2_.c_str(), cert_chain_2_.c_str()));
+}
+
+TEST_F(GrpcTlsCredentialsOptionsTest,
+       ClientOptionsWithCertWatcherProviderOnDeletedFiles) {
+  // Create temporary files and copy cert data into it.
+  auto tmp_root_cert = absl::make_unique<TmpFile>(root_cert_);
+  auto tmp_identity_key = absl::make_unique<TmpFile>(private_key_);
+  auto tmp_identity_cert = absl::make_unique<TmpFile>(cert_chain_);
+  // Create ClientOptions using FileWatcherCertificateProvider.
+  auto options = MakeRefCounted<grpc_tls_credentials_options>();
+  auto provider = MakeRefCounted<FileWatcherCertificateProvider>(
+      tmp_identity_key->name(), tmp_identity_cert->name(),
+      tmp_root_cert->name(), 1);
+  options->set_certificate_provider(std::move(provider));
+  options->set_watch_root_cert(true);
+  options->set_watch_identity_pair(true);
+  options->set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto credentials = MakeRefCounted<TlsCredentials>(options);
+  ASSERT_NE(credentials, nullptr);
+  grpc_channel_args* new_args = nullptr;
+  auto connector = credentials->create_security_connector(
+      nullptr, "random targets", nullptr, &new_args);
+  grpc_channel_args_destroy(new_args);
+  ASSERT_NE(connector, nullptr);
+  TlsChannelSecurityConnector* tls_connector =
+      static_cast<TlsChannelSecurityConnector*>(connector.get());
+  // The initial data is all good, so we expect to have successful credential
+  // updates.
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_);
+  ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+  EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
+            MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+  // Delete TmpFile objects, which will remove the corresponding files.
+  tmp_root_cert.reset();
+  tmp_identity_key.reset();
+  tmp_identity_cert.reset();
+  // Wait 2 seconds for the provider's refresh thread to read the deleted files.
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                               gpr_time_from_seconds(2, GPR_TIMESPAN)));
+  // It's a bit hard to test if errors are sent to the security connector,
+  // because the security connector simply logs the error. We will see the err
+  // messages if we open the log.
+  // The old certs should still being used.
+  EXPECT_NE(tls_connector->ClientHandshakerFactoryForTesting(), nullptr);
+  ASSERT_TRUE(tls_connector->RootCertsForTesting().has_value());
+  EXPECT_EQ(tls_connector->RootCertsForTesting(), root_cert_);
+  ASSERT_TRUE(tls_connector->KeyCertPairListForTesting().has_value());
+  EXPECT_EQ(tls_connector->KeyCertPairListForTesting(),
+            MakeCertKeyPairs(private_key_.c_str(), cert_chain_.c_str()));
+}
+
 }  // namespace testing
 
+}  // namespace grpc_core
+
 int main(int argc, char** argv) {
   grpc::testing::TestEnvironment env(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/test/core/security/tls_utils.cc b/test/core/security/tls_utils.cc
new file mode 100644
index 0000000..4f56ed2
--- /dev/null
+++ b/test/core/security/tls_utils.cc
@@ -0,0 +1,83 @@
+//
+// Copyright 2020 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "test/core/security/tls_utils.h"
+
+#include "src/core/lib/gpr/tmpfile.h"
+#include "src/core/lib/iomgr/load_file.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+namespace grpc_core {
+
+namespace testing {
+
+TmpFile::TmpFile(absl::string_view credential_data) {
+  name_ = CreateTmpFileAndWriteData(credential_data);
+  GPR_ASSERT(!name_.empty());
+}
+
+TmpFile::~TmpFile() { GPR_ASSERT(remove(name_.c_str()) == 0); }
+
+void TmpFile::RewriteFile(absl::string_view credential_data) {
+  // Create a new file containing new data.
+  std::string new_name = CreateTmpFileAndWriteData(credential_data);
+  GPR_ASSERT(!new_name.empty());
+  // Remove the old file.
+  GPR_ASSERT(remove(name_.c_str()) == 0);
+  // Rename the new file to the original name.
+  GPR_ASSERT(rename(new_name.c_str(), name_.c_str()) == 0);
+}
+
+std::string TmpFile::CreateTmpFileAndWriteData(
+    absl::string_view credential_data) {
+  char* name = nullptr;
+  FILE* file_descriptor = gpr_tmpfile("GrpcTlsCertificateProviderTest", &name);
+  GPR_ASSERT(fwrite(credential_data.data(), 1, credential_data.size(),
+                    file_descriptor) == credential_data.size());
+  GPR_ASSERT(fclose(file_descriptor) == 0);
+  GPR_ASSERT(file_descriptor != nullptr);
+  GPR_ASSERT(name != nullptr);
+  std::string name_to_return = name;
+  gpr_free(name);
+  return name_to_return;
+}
+
+PemKeyCertPairList MakeCertKeyPairs(const char* private_key,
+                                    const char* certs) {
+  if (strcmp(private_key, "") == 0 && strcmp(certs, "") == 0) {
+    return {};
+  }
+  grpc_ssl_pem_key_cert_pair* ssl_pair =
+      static_cast<grpc_ssl_pem_key_cert_pair*>(
+          gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
+  ssl_pair->private_key = gpr_strdup(private_key);
+  ssl_pair->cert_chain = gpr_strdup(certs);
+  PemKeyCertPairList pem_key_cert_pairs;
+  pem_key_cert_pairs.emplace_back(ssl_pair);
+  return pem_key_cert_pairs;
+}
+
+std::string GetFileContents(const char* path) {
+  grpc_slice slice = grpc_empty_slice();
+  GPR_ASSERT(GRPC_LOG_IF_ERROR("load_file", grpc_load_file(path, 0, &slice)));
+  std::string credential = std::string(StringViewFromSlice(slice));
+  grpc_slice_unref(slice);
+  return credential;
+}
+
+}  // namespace testing
+
+}  // namespace grpc_core
diff --git a/test/core/security/tls_utils.h b/test/core/security/tls_utils.h
new file mode 100644
index 0000000..94d29ef
--- /dev/null
+++ b/test/core/security/tls_utils.h
@@ -0,0 +1,47 @@
+//
+// Copyright 2020 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "src/core/lib/security/security_connector/ssl_utils.h"
+
+namespace grpc_core {
+
+namespace testing {
+
+class TmpFile {
+ public:
+  // Create a temporary file with |credential_data| written in.
+  explicit TmpFile(absl::string_view credential_data);
+
+  ~TmpFile();
+
+  const std::string& name() { return name_; }
+
+  // Rewrite |credential_data| to the temporary file, in an atomic way.
+  void RewriteFile(absl::string_view credential_data);
+
+ private:
+  std::string CreateTmpFileAndWriteData(absl::string_view credential_data);
+
+  std::string name_;
+};
+
+PemKeyCertPairList MakeCertKeyPairs(const char* private_key, const char* certs);
+
+std::string GetFileContents(const char* path);
+
+}  // namespace testing
+
+}  // namespace grpc_core
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 4b821be..cd0095f 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -206,6 +206,7 @@
   printf("%lx", (unsigned long) grpc_tls_identity_pairs_add_pair);
   printf("%lx", (unsigned long) grpc_tls_identity_pairs_destroy);
   printf("%lx", (unsigned long) grpc_tls_certificate_provider_static_data_create);
+  printf("%lx", (unsigned long) grpc_tls_certificate_provider_file_watcher_create);
   printf("%lx", (unsigned long) grpc_tls_certificate_provider_release);
   printf("%lx", (unsigned long) grpc_tls_credentials_options_create);
   printf("%lx", (unsigned long) grpc_tls_credentials_options_set_cert_request_type);
diff --git a/test/cpp/client/BUILD b/test/cpp/client/BUILD
index ce0f6d3..c62c633 100644
--- a/test/cpp/client/BUILD
+++ b/test/cpp/client/BUILD
@@ -21,6 +21,11 @@
 grpc_cc_test(
     name = "credentials_test",
     srcs = ["credentials_test.cc"],
+    data = [
+        "//src/core/tsi/test_creds:ca.pem",
+        "//src/core/tsi/test_creds:server1.key",
+        "//src/core/tsi/test_creds:server1.pem",
+    ],
     external_deps = [
         "gtest",
     ],
diff --git a/test/cpp/client/credentials_test.cc b/test/cpp/client/credentials_test.cc
index 0d9eaf0..b2ec888 100644
--- a/test/cpp/client/credentials_test.cc
+++ b/test/cpp/client/credentials_test.cc
@@ -32,6 +32,10 @@
 #include "src/cpp/client/secure_credentials.h"
 #include "src/cpp/common/tls_credentials_options_util.h"
 
+#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
+#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
+#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
+
 namespace {
 
 constexpr const char* kRootCertName = "root_cert_name";
@@ -40,6 +44,7 @@
 constexpr const char* kIdentityCertPrivateKey = "identity_private_key";
 constexpr const char* kIdentityCertContents = "identity_cert_contents";
 
+using ::grpc::experimental::FileWatcherCertificateProvider;
 using ::grpc::experimental::StaticDataCertificateProvider;
 using ::grpc::experimental::TlsServerAuthorizationCheckArg;
 using ::grpc::experimental::TlsServerAuthorizationCheckConfig;
@@ -407,6 +412,52 @@
   GPR_ASSERT(channel_credentials.get() != nullptr);
 }
 
+TEST(
+    CredentialsTest,
+    TlsChannelCredentialsWithFileWatcherCertificateProviderLoadingRootAndIdentity) {
+  auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
+  grpc::experimental::TlsChannelCredentialsOptions options(
+      certificate_provider);
+  options.watch_root_certs();
+  options.set_root_cert_name(kRootCertName);
+  options.watch_identity_key_cert_pairs();
+  options.set_identity_cert_name(kIdentityCertName);
+  options.set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto test_server_authorization_check =
+      std::make_shared<TestTlsServerAuthorizationCheck>();
+  auto server_authorization_check_config =
+      std::make_shared<TlsServerAuthorizationCheckConfig>(
+          test_server_authorization_check);
+  options.set_server_authorization_check_config(
+      server_authorization_check_config);
+  auto channel_credentials = grpc::experimental::TlsCredentials(options);
+  GPR_ASSERT(channel_credentials.get() != nullptr);
+}
+
+// ChannelCredentials should always have root credential presented.
+// Otherwise the system root certificates will be loaded, which will cause
+// failure in some tests under MacOS/Windows.
+TEST(CredentialsTest,
+     TlsChannelCredentialsWithFileWatcherCertificateProviderLoadingRootOnly) {
+  auto certificate_provider =
+      std::make_shared<FileWatcherCertificateProvider>(CA_CERT_PATH, 1);
+  grpc::experimental::TlsChannelCredentialsOptions options(
+      certificate_provider);
+  options.watch_root_certs();
+  options.set_root_cert_name(kRootCertName);
+  options.set_server_verification_option(GRPC_TLS_SERVER_VERIFICATION);
+  auto test_server_authorization_check =
+      std::make_shared<TestTlsServerAuthorizationCheck>();
+  auto server_authorization_check_config =
+      std::make_shared<TlsServerAuthorizationCheckConfig>(
+          test_server_authorization_check);
+  options.set_server_authorization_check_config(
+      server_authorization_check_config);
+  auto channel_credentials = grpc::experimental::TlsCredentials(options);
+  GPR_ASSERT(channel_credentials.get() != nullptr);
+}
+
 TEST(CredentialsTest, TlsServerAuthorizationCheckConfigErrorMessages) {
   std::shared_ptr<TlsServerAuthorizationCheckConfig> config(
       new TlsServerAuthorizationCheckConfig(nullptr));
diff --git a/test/cpp/server/BUILD b/test/cpp/server/BUILD
index c2ccd8a..cb1972a 100644
--- a/test/cpp/server/BUILD
+++ b/test/cpp/server/BUILD
@@ -63,6 +63,11 @@
 grpc_cc_test(
     name = "credentials_test",
     srcs = ["credentials_test.cc"],
+    data = [
+        "//src/core/tsi/test_creds:ca.pem",
+        "//src/core/tsi/test_creds:server1.key",
+        "//src/core/tsi/test_creds:server1.pem",
+    ],
     external_deps = [
         "gtest",
     ],
diff --git a/test/cpp/server/credentials_test.cc b/test/cpp/server/credentials_test.cc
index 8e7fc17..3c8dcf7 100644
--- a/test/cpp/server/credentials_test.cc
+++ b/test/cpp/server/credentials_test.cc
@@ -27,6 +27,10 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+#define CA_CERT_PATH "src/core/tsi/test_creds/ca.pem"
+#define SERVER_CERT_PATH "src/core/tsi/test_creds/server1.pem"
+#define SERVER_KEY_PATH "src/core/tsi/test_creds/server1.key"
+
 namespace {
 
 constexpr const char* kRootCertName = "root_cert_name";
@@ -35,6 +39,7 @@
 constexpr const char* kIdentityCertPrivateKey = "identity_private_key";
 constexpr const char* kIdentityCertContents = "identity_cert_contents";
 
+using ::grpc::experimental::FileWatcherCertificateProvider;
 using ::grpc::experimental::StaticDataCertificateProvider;
 
 }  // namespace
@@ -86,6 +91,38 @@
   GPR_ASSERT(server_credentials.get() != nullptr);
 }
 
+TEST(
+    CredentialsTest,
+    TlsServerCredentialsWithFileWatcherCertificateProviderLoadingRootAndIdentity) {
+  auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, CA_CERT_PATH, 1);
+  grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
+  options.watch_root_certs();
+  options.set_root_cert_name(kRootCertName);
+  options.watch_identity_key_cert_pairs();
+  options.set_identity_cert_name(kIdentityCertName);
+  options.set_cert_request_type(
+      GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
+  auto server_credentials = grpc::experimental::TlsServerCredentials(options);
+  GPR_ASSERT(server_credentials.get() != nullptr);
+}
+
+// ServerCredentials should always have identity credential presented.
+// Otherwise gRPC stack will fail.
+TEST(
+    CredentialsTest,
+    TlsServerCredentialsWithFileWatcherCertificateProviderLoadingIdentityOnly) {
+  auto certificate_provider = std::make_shared<FileWatcherCertificateProvider>(
+      SERVER_KEY_PATH, SERVER_CERT_PATH, 1);
+  grpc::experimental::TlsServerCredentialsOptions options(certificate_provider);
+  options.watch_identity_key_cert_pairs();
+  options.set_identity_cert_name(kIdentityCertName);
+  options.set_cert_request_type(
+      GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
+  auto server_credentials = grpc::experimental::TlsServerCredentials(options);
+  GPR_ASSERT(server_credentials.get() != nullptr);
+}
+
 }  // namespace
 }  // namespace testing
 }  // namespace grpc
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 61ac2ff..48bb34f 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -4658,6 +4658,30 @@
     "flaky": false,
     "gtest": true,
     "language": "c++",
+    "name": "grpc_tls_certificate_provider_test",
+    "platforms": [
+      "linux",
+      "mac",
+      "posix",
+      "windows"
+    ],
+    "uses_polling": true
+  },
+  {
+    "args": [],
+    "benchmark": false,
+    "ci_platforms": [
+      "linux",
+      "mac",
+      "posix",
+      "windows"
+    ],
+    "cpu_cost": 1.0,
+    "exclude_configs": [],
+    "exclude_iomgrs": [],
+    "flaky": false,
+    "gtest": true,
+    "language": "c++",
     "name": "grpc_tls_credentials_options_test",
     "platforms": [
       "linux",