diff --git a/.gitignore b/.gitignore
index 01d35d64e78c71576561c45c892462bf54e98fd0..686623d997d442c831256b94e8a13f3c5f1dc091 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,4 @@
 .project
 .classpath
 /.settings
-
+/tests/__pycache__
\ No newline at end of file
diff --git a/kubernetes/helm/openslice/values.yaml b/kubernetes/helm/openslice/values.yaml
index 7ec3d058b9c96626ff9e799983bc86a6cec28238..27415b5cc4ee9b07704311c75c3463f176fcf46b 100644
--- a/kubernetes/helm/openslice/values.yaml
+++ b/kubernetes/helm/openslice/values.yaml
@@ -26,7 +26,7 @@ image:
     # Overrides the image tag whose default is the chart appVersion.
     tag: "develop"
   keycloak:
-    repository: jboss/keycloak
+    repository: quay.io/keycloak/keycloak
     pullPolicy: IfNotPresent
     # Overrides the image tag whose default is the chart appVersion.
     tag: "16.1.1"
diff --git a/tests/end_to_end_tests.py b/tests/end_to_end_tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..327012a0777bb1d9df20b33031566f9534e4bee0
--- /dev/null
+++ b/tests/end_to_end_tests.py
@@ -0,0 +1,71 @@
+import subprocess
+import pytest
+import time
+
+print("starting")
+release_name = "test-openslice"
+
+def run_command(command):
+    """ Helper function to run a command with detailed error logging. """
+    try:
+        result = subprocess.run(command, capture_output=True, text=True, check=True)
+        print(f"Command {' '.join(command)}: {result.stdout}")
+        return result
+    except subprocess.CalledProcessError as e:
+        print(f"Failed to execute {' '.join(command)}: {e.stderr}")
+        raise
+
+def get_pods(release_name):
+    """Retrieve list of pod names for a given release."""
+    time.sleep(3)
+    cmd = ["kubectl", "get", "pods", "-l", f"app={release_name}", "-o", "name"]
+    result = run_command(cmd)
+    pod_names = result.stdout.strip().split()
+    print(pod_names)
+    return [name.split('/')[-1] for name in pod_names]  # Convert 'pod/my-pod-name' to 'my-pod-name'
+
+@pytest.fixture(scope="module")
+def deploy_helm():
+    print("Deploying Helm chart...")
+    run_command(["helm", "install", release_name, "kubernetes/helm/openslice", "--namespace", "openslice", "-f", "kubernetes/helm/openslice/values.yaml"])
+    yield "test-openslice"
+    print("Uninstalling Helm chart...")
+    run_command(["helm", "uninstall", release_name, "--namespace", "openslice"])
+
+def check_pod_readiness(pod_name):
+    result = run_command(["kubectl", "get", "pod", pod_name, "-o", "jsonpath='{.status.phase}'"])
+    return result.stdout.strip() == "'Running'"
+
+def wait_for_pods_ready(pod_names, timeout=300):
+    start_time = time.time()
+    while True:
+        all_ready = True
+        for pod_name in pod_names:
+            if not check_pod_readiness(pod_name):
+                all_ready = False
+                break
+        if all_ready:
+            print("All pods are ready.")
+            time.sleep(45)  # Wait for 5 seconds before returning
+            return True
+        elif time.time() - start_time > timeout:
+            print("Timeout reached, pods not ready.")
+            return False
+        else:
+            time.sleep(10)  # Wait for 10 seconds before checking again
+            print()
+
+@pytest.mark.usefixtures("deploy_helm")
+class TestApplicationComponents:
+    def test_pods_readiness(self, deploy_helm):
+        release_name = deploy_helm
+        pod_names = get_pods(release_name)
+        assert wait_for_pods_ready(pod_names), "Not all pods were ready in time"
+
+# Something is very strange here. The pods are not all running. Some are in CrashLoopBackOff state. But the test is saying all are running.
+# Questions:
+# 1. What is a fixture?
+# 2. What is a scope?
+# 3. What is a yield?
+# 4. What is a module?
+# 5. How can I group tests together so they run like subtests, for example subtests of helm install is having all pods be ready.