Repository: deepset-ai/haystack

Issue:
Make `DeepsetCloudDocumentStore` work with non-existing index
We want to allow users to connect to the DC docstore without having to create a pipeline first. This will enable the worflow to create a pipeline from scratch using the DC SDK. 

Implementation: 
 - Set default index value to `None`
 - Make sure `info()` call does not raise an exception if index = `None` or specified index does not exist
 - always returns empty results for document stores that do not use an existing index
 - Logging of warnings such as `You are using a deepset cloud document store without an index. This document store will always return empty responses. To add files to your index, first upload files and publish&deploy your pipeline. DC will automatically index your files for you.`


Discussion:

Resolving patch:
diff --git a/haystack/document_stores/deepsetcloud.py b/haystack/document_stores/deepsetcloud.py
--- a/haystack/document_stores/deepsetcloud.py
+++ b/haystack/document_stores/deepsetcloud.py
@@ -6,8 +6,7 @@
 
 from haystack.document_stores import KeywordDocumentStore
 from haystack.schema import Document, Label
-from haystack.utils import DeepsetCloud
-
+from haystack.utils import DeepsetCloud, DeepsetCloudError
 
 logger = logging.getLogger(__name__)
 
@@ -17,7 +16,7 @@ def __init__(
         self,
         api_key: str = None,
         workspace: str = "default",
-        index: str = "default",
+        index: Optional[str] = None,
         duplicate_documents: str = "overwrite",
         api_endpoint: Optional[str] = None,
         similarity: str = "dot_product",
@@ -25,25 +24,37 @@ def __init__(
         label_index: str = "default",
     ):
         """
-        A DocumentStore facade enabling you to interact with the documents stored in Deepset Cloud.
+        A DocumentStore facade enabling you to interact with the documents stored in deepset Cloud.
         Thus you can run experiments like trying new nodes, pipelines, etc. without having to index your data again.
 
+        You can also use this DocumentStore to create new pipelines on deepset Cloud. To do that, take the following
+        steps:
+
+        - create a new DeepsetCloudDocumentStore without an index (e.g. `DeepsetCloudDocumentStore()`)
+        - create query and indexing pipelines using this DocumentStore
+        - call `Pipeline.save_to_deepset_cloud()` passing the pipelines and a `pipeline_config_name`
+        - call `Pipeline.deploy_on_deepset_cloud()` passing the `pipeline_config_name`
+
         DeepsetCloudDocumentStore is not intended for use in production-like scenarios.
-        See https://haystack.deepset.ai/components/document-store for more information.
+        See [https://haystack.deepset.ai/components/document-store](https://haystack.deepset.ai/components/document-store)
+        for more information.
 
         :param api_key: Secret value of the API key.
                         If not specified, will be read from DEEPSET_CLOUD_API_KEY environment variable.
                         See docs on how to generate an API key for your workspace: https://docs.cloud.deepset.ai/docs/connect-deepset-cloud-to-your-application
-        :param workspace: workspace name in Deepset Cloud
-        :param index: name of the index to access within the Deepset Cloud workspace. This equals typically the name of your pipeline.
-                      You can run Pipeline.list_pipelines_on_deepset_cloud() to see all available ones.
+        :param workspace: workspace name in deepset Cloud
+        :param index: name of the index to access within the deepset Cloud workspace. This equals typically the name of
+                      your pipeline. You can run Pipeline.list_pipelines_on_deepset_cloud() to see all available ones.
+                      If you set index to `None`, this DocumentStore will always return empty results.
+                      This is especially useful if you want to create a new Pipeline within deepset Cloud
+                      (see Pipeline.save_to_deepset_cloud()` and `Pipeline.deploy_on_deepset_cloud()`).
         :param duplicate_documents: Handle duplicates document based on parameter options.
                                     Parameter options : ( 'skip','overwrite','fail')
                                     skip: Ignore the duplicates documents
                                     overwrite: Update any existing documents with the same ID when adding documents.
                                     fail: an error is raised if the document ID of the document being added already
                                     exists.
-        :param api_endpoint: The URL of the Deepset Cloud API.
+        :param api_endpoint: The URL of the deepset Cloud API.
                              If not specified, will be read from DEEPSET_CLOUD_API_ENDPOINT environment variable.
                              If DEEPSET_CLOUD_API_ENDPOINT environment variable is not specified either, defaults to "https://api.cloud.deepset.ai/api/v1".
         :param similarity: The similarity function used to compare document vectors. 'dot_product' is the default since it is
@@ -61,12 +72,45 @@ def __init__(
         self.client = DeepsetCloud.get_index_client(
             api_key=api_key, api_endpoint=api_endpoint, workspace=workspace, index=index
         )
-
-        index_info = self.client.info()
-        indexing_info = index_info["indexing"]
-        if indexing_info["pending_file_count"] > 0:
-            logger.warning(
-                f"{indexing_info['pending_file_count']} files are pending to be indexed. Indexing status: {indexing_info['status']}"
+        # Check if index exists
+        pipeline_client = DeepsetCloud.get_pipeline_client(
+            api_key=api_key, api_endpoint=api_endpoint, workspace=workspace
+        )
+        deployed_pipelines = set()
+        deployed_unhealthy_pipelines = set()
+        try:
+            for pipe in pipeline_client.list_pipeline_configs(workspace=workspace):
+                if pipe["status"] == "DEPLOYED":
+                    deployed_pipelines.add(pipe["name"])
+                elif pipe["status"] == "DEPLOYED_UNHEALTHY":
+                    deployed_unhealthy_pipelines.add(pipe["name"])
+        except Exception as ie:
+            raise DeepsetCloudError(f"Could not connect to deepset Cloud:\n{ie}") from ie
+
+        self.index_exists = index in deployed_pipelines | deployed_unhealthy_pipelines
+
+        if self.index_exists:
+            index_info = self.client.info()
+            indexing_info = index_info["indexing"]
+            if indexing_info["pending_file_count"] > 0:
+                logger.warning(
+                    f"{indexing_info['pending_file_count']} files are pending to be indexed. "
+                    f"Indexing status: {indexing_info['status']}"
+                )
+            if index in deployed_unhealthy_pipelines:
+                logger.warning(
+                    f"The index '{index}' is unhealthy and should be redeployed using "
+                    f"`Pipeline.undeploy_on_deepset_cloud()` and `Pipeline.deploy_on_deepset_cloud()`."
+                )
+        else:
+            logger.info(
+                f"You are using a DeepsetCloudDocumentStore with an index that does not exist on deepset Cloud. "
+                f"This document store will always return empty responses. This is especially useful if you want to "
+                f"create a new pipeline within deepset Cloud.\n"
+                f"In order to create a new pipeline on deepset Cloud, take the following steps: \n"
+                f"  - create query and indexing pipelines using this DocumentStore\n"
+                f"  - call `Pipeline.save_to_deepset_cloud()` passing the pipelines and a `pipeline_config_name`\n"
+                f"  - call `Pipeline.deploy_on_deepset_cloud()` passing the `pipeline_config_name`"
             )
 
         self.evaluation_set_client = DeepsetCloud.get_evaluation_set_client(
@@ -119,9 +163,10 @@ def get_all_documents(
         :param headers: Custom HTTP headers to pass to document store client if supported (e.g. {'Authorization': 'Basic YWRtaW46cm9vdA=='} for basic authentication)
         """
         logging.warning(
-            "`get_all_documents()` can get very slow and resource-heavy since all documents must be loaded from Deepset Cloud. "
+            "`get_all_documents()` can get very slow and resource-heavy since all documents must be loaded from deepset Cloud. "
             "Consider using `get_all_documents_generator()` instead."
         )
+
         return list(
             self.get_all_documents_generator(
                 index=index, filters=filters, return_embedding=return_embedding, batch_size=batch_size, headers=headers
@@ -173,6 +218,9 @@ def get_all_documents_generator(
         :param batch_size: When working with large number of documents, batching can help reduce memory footprint.
         :param headers: Custom HTTP headers to pass to document store client if supported (e.g. {'Authorization': 'Basic YWRtaW46cm9vdA=='} for basic authentication)
         """
+        if not self.index_exists:
+            return
+
         if batch_size != 10_000:
             raise ValueError("DeepsetCloudDocumentStore does not support batching")
 
@@ -192,6 +240,9 @@ def get_all_documents_generator(
     def get_document_by_id(
         self, id: str, index: Optional[str] = None, headers: Optional[Dict[str, str]] = None
     ) -> Optional[Document]:
+        if not self.index_exists:
+            return None
+
         if index is None:
             index = self.index
 
@@ -209,6 +260,9 @@ def get_documents_by_id(
         batch_size: int = 10_000,
         headers: Optional[Dict[str, str]] = None,
     ) -> List[Document]:
+        if not self.index_exists:
+            return []
+
         if batch_size != 10_000:
             raise ValueError("DeepsetCloudDocumentStore does not support batching")
 
@@ -222,6 +276,9 @@ def get_document_count(
         only_documents_without_embedding: bool = False,
         headers: Optional[Dict[str, str]] = None,
     ) -> int:
+        if not self.index_exists:
+            return 0
+
         count_result = self.client.count_documents(
             filters=filters,
             only_documents_without_embedding=only_documents_without_embedding,
@@ -316,6 +373,9 @@ def query_by_embedding(
                             Otherwise raw similarity scores (e.g. cosine or dot_product) will be used.
         :return:
         """
+        if not self.index_exists:
+            return []
+
         if return_embedding is None:
             return_embedding = self.return_embedding
 
@@ -423,6 +483,9 @@ def query(
                             If true (default) similarity scores (e.g. cosine or dot_product) which naturally have a different value range will be scaled to a range of [0,1], where 1 means extremely relevant.
                             Otherwise raw similarity scores (e.g. cosine or dot_product) will be used.
         """
+        if not self.index_exists:
+            return []
+
         doc_dicts = self.client.query(
             query=query,
             filters=filters,
diff --git a/haystack/utils/deepsetcloud.py b/haystack/utils/deepsetcloud.py
--- a/haystack/utils/deepsetcloud.py
+++ b/haystack/utils/deepsetcloud.py
@@ -66,17 +66,17 @@ def __call__(self, r):
 
 
 class DeepsetCloudError(Exception):
-    """Raised when there is an error communicating with Deepset Cloud"""
+    """Raised when there is an error communicating with deepset Cloud"""
 
 
 class DeepsetCloudClient:
     def __init__(self, api_key: str = None, api_endpoint: Optional[str] = None):
         """
-        A client to communicate with Deepset Cloud.
+        A client to communicate with deepset Cloud.
 
         :param api_key: Secret value of the API key.
                         If not specified, will be read from DEEPSET_CLOUD_API_KEY environment variable.
-        :param api_endpoint: The URL of the Deepset Cloud API.
+        :param api_endpoint: The URL of the deepset Cloud API.
                              If not specified, will be read from DEEPSET_CLOUD_API_ENDPOINT environment variable.
         """
         self.api_key = api_key or os.getenv("DEEPSET_CLOUD_API_KEY")
@@ -285,11 +285,11 @@ def _remove_null_values(self, body: dict) -> dict:
 class IndexClient:
     def __init__(self, client: DeepsetCloudClient, workspace: Optional[str] = None, index: Optional[str] = None):
         """
-        A client to communicate with Deepset Cloud indexes.
+        A client to communicate with deepset Cloud indexes.
 
-        :param client: Deepset Cloud client
-        :param workspace: workspace in Deepset Cloud
-        :param index: index in Deepset Cloud workspace
+        :param client: deepset Cloud client
+        :param workspace: workspace in deepset Cloud
+        :param index: index in deepset Cloud workspace
 
         """
         self.client = client
@@ -302,7 +302,7 @@ def info(self, workspace: Optional[str] = None, index: Optional[str] = None, hea
             response = self.client.get(url=index_url, headers=headers)
             return response.json()
         except Exception as ie:
-            raise DeepsetCloudError(f"Could not connect to Deepset Cloud:\n{ie}") from ie
+            raise DeepsetCloudError(f"Could not connect to deepset Cloud:\n{ie}") from ie
 
     def query(
         self,
@@ -366,7 +366,7 @@ def get_document(
             doc = response.json()
         else:
             logger.warning(
-                f"Document {id} could not be fetched from Deepset Cloud: HTTP {response.status_code} - {response.reason}\n{response.content.decode()}"
+                f"Document {id} could not be fetched from deepset Cloud: HTTP {response.status_code} - {response.reason}\n{response.content.decode()}"
             )
         return doc
 
@@ -398,11 +398,11 @@ def __init__(
         self, client: DeepsetCloudClient, workspace: Optional[str] = None, pipeline_config_name: Optional[str] = None
     ):
         """
-        A client to communicate with Deepset Cloud pipelines.
+        A client to communicate with deepset Cloud pipelines.
 
-        :param client: Deepset Cloud client
-        :param workspace: workspace in Deepset Cloud
-        :param pipeline_config_name: name of the pipeline_config in Deepset Cloud workspace
+        :param client: deepset Cloud client
+        :param workspace: workspace in deepset Cloud
+        :param pipeline_config_name: name of the pipeline_config in deepset Cloud workspace
 
         """
         self.client = client
@@ -469,14 +469,14 @@ def deploy(
         self, pipeline_config_name: Optional[str] = None, workspace: str = None, headers: dict = None, timeout: int = 60
     ):
         """
-        Deploys the pipelines of a pipeline config on Deepset Cloud.
+        Deploys the pipelines of a pipeline config on deepset Cloud.
         Blocks until pipelines are successfully deployed, deployment failed or timeout exceeds.
         If pipelines are already deployed no action will be taken and an info will be logged.
         If timeout exceeds a TimeoutError will be raised.
         If deployment fails a DeepsetCloudError will be raised.
 
-        :param pipeline_config_name: name of the config file inside the Deepset Cloud workspace.
-        :param workspace: workspace in Deepset Cloud
+        :param pipeline_config_name: name of the config file inside the deepset Cloud workspace.
+        :param workspace: workspace in deepset Cloud
         :param headers: Headers to pass to API call
         :param timeout: The time in seconds to wait until deployment completes.
                         If the timeout is exceeded an error will be raised.
@@ -500,7 +500,7 @@ def deploy(
             )
         elif status in [PipelineStatus.UNDEPLOYMENT_IN_PROGRESS, PipelineStatus.UNDEPLOYMENT_SCHEDULED]:
             raise DeepsetCloudError(
-                f"Deployment of pipline config '{pipeline_config_name}' aborted. Undeployment was requested."
+                f"Deployment of pipeline config '{pipeline_config_name}' aborted. Undeployment was requested."
             )
         elif status == PipelineStatus.UNDEPLOYED:
             raise DeepsetCloudError(f"Deployment of pipeline config '{pipeline_config_name}' failed.")
@@ -513,14 +513,14 @@ def undeploy(
         self, pipeline_config_name: Optional[str] = None, workspace: str = None, headers: dict = None, timeout: int = 60
     ):
         """
-        Undeploys the pipelines of a pipeline config on Deepset Cloud.
+        Undeploys the pipelines of a pipeline config on deepset Cloud.
         Blocks until pipelines are successfully undeployed, undeployment failed or timeout exceeds.
         If pipelines are already undeployed no action will be taken and an info will be logged.
         If timeout exceeds a TimeoutError will be raised.
         If deployment fails a DeepsetCloudError will be raised.
 
-        :param pipeline_config_name: name of the config file inside the Deepset Cloud workspace.
-        :param workspace: workspace in Deepset Cloud
+        :param pipeline_config_name: name of the config file inside the deepset Cloud workspace.
+        :param workspace: workspace in deepset Cloud
         :param headers: Headers to pass to API call
         :param timeout: The time in seconds to wait until undeployment completes.
                         If the timeout is exceeded an error will be raised.
@@ -540,7 +540,7 @@ def undeploy(
                 logger.info(f"Pipeline config '{pipeline_config_name}' is already undeployed.")
         elif status in [PipelineStatus.DEPLOYMENT_IN_PROGRESS, PipelineStatus.DEPLOYMENT_SCHEDULED]:
             raise DeepsetCloudError(
-                f"Undeployment of pipline config '{pipeline_config_name}' aborted. Deployment was requested."
+                f"Undeployment of pipeline config '{pipeline_config_name}' aborted. Deployment was requested."
             )
         elif status in [PipelineStatus.DEPLOYED, PipelineStatus.DEPLOYED_UNHEALTHY]:
             raise DeepsetCloudError(f"Undeployment of pipeline config '{pipeline_config_name}' failed.")
@@ -558,11 +558,11 @@ def _transition_pipeline_state(
         headers: dict = None,
     ) -> Tuple[PipelineStatus, bool]:
         """
-        Transitions the pipeline config state to desired target_state on Deepset Cloud.
+        Transitions the pipeline config state to desired target_state on deepset Cloud.
 
         :param target_state: the target state of the Pipeline config.
-        :param pipeline_config_name: name of the config file inside the Deepset Cloud workspace.
-        :param workspace: workspace in Deepset Cloud
+        :param pipeline_config_name: name of the config file inside the deepset Cloud workspace.
+        :param workspace: workspace in deepset Cloud
         :param headers: Headers to pass to API call
         :param timeout: The time in seconds to wait until undeployment completes.
                         If the timeout is exceeded an error will be raised.
@@ -647,10 +647,10 @@ def __init__(
         self, client: DeepsetCloudClient, workspace: Optional[str] = None, evaluation_set: Optional[str] = None
     ):
         """
-        A client to communicate with Deepset Cloud evaluation sets and labels.
+        A client to communicate with deepset Cloud evaluation sets and labels.
 
-        :param client: Deepset Cloud client
-        :param workspace: workspace in Deepset Cloud
+        :param client: deepset Cloud client
+        :param workspace: workspace in deepset Cloud
         :param evaluation_set: name of the evaluation set to fall back to
 
         """
@@ -664,7 +664,7 @@ def get_labels(self, evaluation_set: Optional[str], workspace: Optional[str] = N
         If no labels were found, raises DeepsetCloudError.
 
         :param evaluation_set: name of the evaluation set for which labels should be fetched
-        :param workspace: Optional workspace in Deepset Cloud
+        :param workspace: Optional workspace in deepset Cloud
                           If None, the EvaluationSetClient's default workspace (self.workspace) will be used.
 
         :return: list of Label
@@ -721,9 +721,9 @@ def get_labels_count(self, evaluation_set: Optional[str] = None, workspace: Opti
 
     def get_evaluation_sets(self, workspace: Optional[str] = None) -> List[dict]:
         """
-        Searches for all evaluation set names in the given workspace in Deepset Cloud.
+        Searches for all evaluation set names in the given workspace in deepset Cloud.
 
-        :param workspace: Optional workspace in Deepset Cloud
+        :param workspace: Optional workspace in deepset Cloud
                           If None, the EvaluationSetClient's default workspace (self.workspace) will be used.
 
         :return: List of dictionaries that represent deepset Cloud evaluation sets.
@@ -760,7 +760,7 @@ def _build_workspace_url(self, workspace: Optional[str] = None):
 
 class DeepsetCloud:
     """
-    A facade to communicate with Deepset Cloud.
+    A facade to communicate with deepset Cloud.
     """
 
     @classmethod
@@ -772,14 +772,14 @@ def get_index_client(
         index: Optional[str] = None,
     ) -> IndexClient:
         """
-        Creates a client to communicate with Deepset Cloud indexes.
+        Creates a client to communicate with deepset Cloud indexes.
 
         :param api_key: Secret value of the API key.
                         If not specified, will be read from DEEPSET_CLOUD_API_KEY environment variable.
-        :param api_endpoint: The URL of the Deepset Cloud API.
+        :param api_endpoint: The URL of the deepset Cloud API.
                              If not specified, will be read from DEEPSET_CLOUD_API_ENDPOINT environment variable.
-        :param workspace: workspace in Deepset Cloud
-        :param index: index in Deepset Cloud workspace
+        :param workspace: workspace in deepset Cloud
+        :param index: index in deepset Cloud workspace
 
         """
         client = DeepsetCloudClient(api_key=api_key, api_endpoint=api_endpoint)
@@ -794,14 +794,14 @@ def get_pipeline_client(
         pipeline_config_name: Optional[str] = None,
     ) -> PipelineClient:
         """
-        Creates a client to communicate with Deepset Cloud pipelines.
+        Creates a client to communicate with deepset Cloud pipelines.
 
         :param api_key: Secret value of the API key.
                         If not specified, will be read from DEEPSET_CLOUD_API_KEY environment variable.
-        :param api_endpoint: The URL of the Deepset Cloud API.
+        :param api_endpoint: The URL of the deepset Cloud API.
                              If not specified, will be read from DEEPSET_CLOUD_API_ENDPOINT environment variable.
-        :param workspace: workspace in Deepset Cloud
-        :param pipeline_config_name: name of the pipeline_config in Deepset Cloud workspace
+        :param workspace: workspace in deepset Cloud
+        :param pipeline_config_name: name of the pipeline_config in deepset Cloud workspace
 
         """
         client = DeepsetCloudClient(api_key=api_key, api_endpoint=api_endpoint)
@@ -816,14 +816,14 @@ def get_evaluation_set_client(
         evaluation_set: str = "default",
     ) -> EvaluationSetClient:
         """
-        Creates a client to communicate with Deepset Cloud labels.
+        Creates a client to communicate with deepset Cloud labels.
 
         :param api_key: Secret value of the API key.
                         If not specified, will be read from DEEPSET_CLOUD_API_KEY environment variable.
-        :param api_endpoint: The URL of the Deepset Cloud API.
+        :param api_endpoint: The URL of the deepset Cloud API.
                              If not specified, will be read from DEEPSET_CLOUD_API_ENDPOINT environment variable.
-        :param workspace: workspace in Deepset Cloud
-        :param evaluation_set: name of the evaluation set in Deepset Cloud
+        :param workspace: workspace in deepset Cloud
+        :param evaluation_set: name of the evaluation set in deepset Cloud
 
         """
         client = DeepsetCloudClient(api_key=api_key, api_endpoint=api_endpoint)


Test patch:
diff --git a/test/conftest.py b/test/conftest.py
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -399,6 +399,22 @@ def deepset_cloud_fixture():
             json={"indexing": {"status": "INDEXED", "pending_file_count": 0, "total_file_count": 31}},
             status=200,
         )
+        responses.add(
+            method=responses.GET,
+            url=f"{DC_API_ENDPOINT}/workspaces/default/pipelines",
+            match=[responses.matchers.header_matcher({"authorization": f"Bearer {DC_API_KEY}"})],
+            json={
+                "data": [
+                    {
+                        "name": DC_TEST_INDEX,
+                        "status": "DEPLOYED",
+                        "indexing": {"status": "INDEXED", "pending_file_count": 0, "total_file_count": 31},
+                    }
+                ],
+                "has_more": False,
+                "total": 1,
+            },
+        )
     else:
         responses.add_passthru(DC_API_ENDPOINT)
 
diff --git a/test/test_document_store.py b/test/test_document_store.py
--- a/test/test_document_store.py
+++ b/test/test_document_store.py
@@ -1,3 +1,4 @@
+import logging
 from typing import List
 from uuid import uuid4
 
@@ -1505,7 +1506,7 @@ def test_DeepsetCloudDocumentStore_invalid_token():
     if MOCK_DC:
         responses.add(
             method=responses.GET,
-            url=f"{DC_API_ENDPOINT}/workspaces/default/indexes/{DC_TEST_INDEX}",
+            url=f"{DC_API_ENDPOINT}/workspaces/default/pipelines",
             match=[matchers.header_matcher({"authorization": "Bearer invalid_token"})],
             body="Internal Server Error",
             status=500,
@@ -1513,7 +1514,7 @@ def test_DeepsetCloudDocumentStore_invalid_token():
 
     with pytest.raises(
         DeepsetCloudError,
-        match=f"Could not connect to Deepset Cloud:\nGET {DC_API_ENDPOINT}/workspaces/default/indexes/{DC_TEST_INDEX} failed: HTTP 500 - Internal Server Error",
+        match=f"Could not connect to deepset Cloud:\nGET {DC_API_ENDPOINT}/workspaces/default/pipelines failed: HTTP 500 - Internal Server Error",
     ):
         DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key="invalid_token", index=DC_TEST_INDEX)
 
@@ -1523,22 +1524,20 @@ def test_DeepsetCloudDocumentStore_invalid_token():
 def test_DeepsetCloudDocumentStore_invalid_api_endpoint():
     if MOCK_DC:
         responses.add(
-            method=responses.GET,
-            url=f"{DC_API_ENDPOINT}00/workspaces/default/indexes/{DC_TEST_INDEX}",
-            body="Not Found",
-            status=404,
+            method=responses.GET, url=f"{DC_API_ENDPOINT}00/workspaces/default/pipelines", body="Not Found", status=404
         )
 
     with pytest.raises(
         DeepsetCloudError,
-        match=f"Could not connect to Deepset Cloud:\nGET {DC_API_ENDPOINT}00/workspaces/default/indexes/{DC_TEST_INDEX} failed: HTTP 404 - Not Found",
+        match=f"Could not connect to deepset Cloud:\nGET {DC_API_ENDPOINT}00/workspaces/default/pipelines failed: "
+        f"HTTP 404 - Not Found\nNot Found",
     ):
         DeepsetCloudDocumentStore(api_endpoint=f"{DC_API_ENDPOINT}00", api_key=DC_API_KEY, index=DC_TEST_INDEX)
 
 
 @pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
 @responses.activate
-def test_DeepsetCloudDocumentStore_invalid_index():
+def test_DeepsetCloudDocumentStore_invalid_index(caplog):
     if MOCK_DC:
         responses.add(
             method=responses.GET,
@@ -1547,11 +1546,12 @@ def test_DeepsetCloudDocumentStore_invalid_index():
             status=404,
         )
 
-    with pytest.raises(
-        DeepsetCloudError,
-        match=f"Could not connect to Deepset Cloud:\nGET {DC_API_ENDPOINT}/workspaces/default/indexes/invalid_index failed: HTTP 404 - Not Found",
-    ):
+    with caplog.at_level(logging.INFO):
         DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index="invalid_index")
+        assert (
+            "You are using a DeepsetCloudDocumentStore with an index that does not exist on deepset Cloud."
+            in caplog.text
+        )
 
 
 @responses.activate
@@ -1883,6 +1883,56 @@ def test_DeepsetCloudDocumentStore_query_by_embedding(deepset_cloud_document_sto
     assert len(emb_docs) == 0
 
 
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_get_all_docs_without_index():
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert document_store.get_all_documents() == []
+
+
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_get_all_docs_generator_without_index():
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert list(document_store.get_all_documents_generator()) == []
+
+
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_get_doc_by_id_without_index():
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert document_store.get_document_by_id(id="some id") == None
+
+
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_get_docs_by_id_without_index():
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert document_store.get_documents_by_id(ids=["some id"]) == []
+
+
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_get_doc_count_without_index():
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert document_store.get_document_count() == 0
+
+
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_query_by_emb_without_index():
+    query_emb = np.random.randn(768)
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert document_store.query_by_embedding(query_emb=query_emb) == []
+
+
+@pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
+@responses.activate
+def test_DeepsetCloudDocumentStore_query_without_index():
+    document_store = DeepsetCloudDocumentStore(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY, index=None)
+    assert document_store.query(query="some query") == []
+
+
 @pytest.mark.elasticsearch
 def test_elasticsearch_search_field_mapping():
 
diff --git a/test/test_pipeline.py b/test/test_pipeline.py
--- a/test/test_pipeline.py
+++ b/test/test_pipeline.py
@@ -745,31 +745,9 @@ def test_load_from_deepset_cloud_indexing():
 @pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
 @responses.activate
 def test_list_pipelines_on_deepset_cloud():
-    if MOCK_DC:
-        responses.add(
-            method=responses.GET,
-            url=f"{DC_API_ENDPOINT}/workspaces/default/pipelines",
-            json={
-                "data": [
-                    {
-                        "name": "test_pipeline_config",
-                        "pipeline_id": "2184e0c1-c6ec-40a1-9b28-5d2768e5efa2",
-                        "status": "DEPLOYED",
-                        "created_at": "2022-02-01T09:57:03.803991+00:00",
-                        "deleted": False,
-                        "is_default": False,
-                        "indexing": {"status": "IN_PROGRESS", "pending_file_count": 4, "total_file_count": 33},
-                    }
-                ],
-                "has_more": False,
-                "total": 1,
-            },
-            status=200,
-        )
-
     pipelines = Pipeline.list_pipelines_on_deepset_cloud(api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY)
     assert len(pipelines) == 1
-    assert pipelines[0]["name"] == "test_pipeline_config"
+    assert pipelines[0]["name"] == DC_TEST_INDEX
 
 
 @pytest.mark.usefixtures(deepset_cloud_fixture.__name__)
@@ -1202,7 +1180,7 @@ def test_deploy_on_deepset_cloud_invalid_state_in_progress():
             )
     with pytest.raises(
         DeepsetCloudError,
-        match="Deployment of pipline config 'test_new_non_existing_pipeline' aborted. Undeployment was requested.",
+        match="Deployment of pipeline config 'test_new_non_existing_pipeline' aborted. Undeployment was requested.",
     ):
         Pipeline.deploy_on_deepset_cloud(
             pipeline_config_name="test_new_non_existing_pipeline", api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY
@@ -1231,7 +1209,7 @@ def test_undeploy_on_deepset_cloud_invalid_state_in_progress():
             )
     with pytest.raises(
         DeepsetCloudError,
-        match="Undeployment of pipline config 'test_new_non_existing_pipeline' aborted. Deployment was requested.",
+        match="Undeployment of pipeline config 'test_new_non_existing_pipeline' aborted. Deployment was requested.",
     ):
         Pipeline.undeploy_on_deepset_cloud(
             pipeline_config_name="test_new_non_existing_pipeline", api_endpoint=DC_API_ENDPOINT, api_key=DC_API_KEY