diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9be483e093da972d02b0bb66766e583f112a46b6..6645dcd9bb1184754fab3fb42f0afee319e0446e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,19 @@
 # https://hub.docker.com/r/library/python/tags/
 image: python:3.6
 
-#### Entering th release zone
+variables:
+    PYTHONUNBUFFERED: 1
+
+functionnal:
+    stage: test
+    script:
+    - pip install .
+    # Alternative keyring (plain text/for testing purpose only)
+    - pip install keyrings.alt
+    - keyring --list-backends
+    - python sharelatex/tests/functionnal.py
+
+#### Entering the release zone
 pages:
     stage: deploy
     tags: [qlf-ci.inria.fr]
diff --git a/sharelatex/__init__.py b/sharelatex/__init__.py
index 32de03e18fea43af9fa3621ed58e1db2aaeb7cbc..d051c46c31c13374870ceed346843897d13008c2 100644
--- a/sharelatex/__init__.py
+++ b/sharelatex/__init__.py
@@ -571,3 +571,30 @@ class SyncClient:
         r.raise_for_status()
         response = r.json()
         return response
+
+    def new(self, project_name):
+        """Create a new example project for the current user.
+
+        Args:
+            project_name (str): The project name of the project to create
+        """
+        url = f"{self.base_url}/project/new"
+
+        data = {"_csrf": self.csrf, "projectName": project_name, "template": "example"}
+        r = self._post(url, data=data, verify=self.verify)
+        r.raise_for_status()
+        response = r.json()
+        return response
+
+    def delete(self, project_id, *, forever=False):
+        """Delete a project for the current user.
+
+        Args:
+            project_id (str): The project id of the project to delete
+        """
+        url = f"{self.base_url}/project/{project_id}"
+        data = {"_csrf": self.csrf}
+        params = {"forever": forever}
+        r = self._delete(url, data=data, params=params, verify=self.verify)
+        r.raise_for_status()
+        return r
diff --git a/sharelatex/tests/functionnal.py b/sharelatex/tests/functionnal.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc698c9175c9fdb89e572473e875e168738aa58d
--- /dev/null
+++ b/sharelatex/tests/functionnal.py
@@ -0,0 +1,56 @@
+from contextlib import contextmanager
+import os
+from sharelatex import SyncClient
+from subprocess import check_call
+import tempfile
+
+BASE_URL = os.environ.get("CI_BASE_URL")
+USERNAME = os.environ.get("CI_USERNAME")
+PASSWORD = os.environ.get("CI_PASSWORD")
+
+
+def log(f):
+    def wrapped(*args, **kwargs):
+        print("-"*60)
+        print("{:^60}".format(f.__name__.upper()))
+        print("-"*60)
+        return f(*args, **kwargs)
+    return wrapped
+
+@contextmanager
+def project(project_name):
+    client = SyncClient(base_url=BASE_URL, username=USERNAME, password=PASSWORD)
+    with tempfile.TemporaryDirectory() as temp_path:
+        os.chdir(temp_path)
+        r = client.new(project_name)
+        project_id = r["project_id"]
+        path = os.path.join(temp_path, project_id)
+        # TODO(msimonin) yield the repo object also
+        yield (client, path, project_id)
+        client.delete(project_id, forever=True)
+
+
+@log
+def clone():
+    with project("clone") as (_, _, project_id):
+        url = f"{BASE_URL}/project/{project_id}"
+        check_call(
+            f"git slatex clone {url} --username={USERNAME} --password={PASSWORD} --save-password",
+            shell=True,
+        )
+
+@log
+def clone_and_pull():
+    with project("clone_and_pull") as (_, path, project_id):
+        url = f"{BASE_URL}/project/{project_id}"
+        check_call(
+            f"git slatex clone {url} --username={USERNAME} --password={PASSWORD} --save-password",
+            shell=True,
+        )
+        os.chdir(path)
+        check_call("git slatex pull", shell=True)
+
+
+if __name__ == "__main__":
+    clone()
+    clone_and_pull()