diff --git a/remotespark/livyclientlib/livyclientfactory.py b/remotespark/livyclientlib/livyclientfactory.py
index f7b2ae3..3bdda7f 100644
--- a/remotespark/livyclientlib/livyclientfactory.py
+++ b/remotespark/livyclientlib/livyclientfactory.py
@@ -30,11 +30,15 @@ class LivyClientFactory(object):
 
     @staticmethod
     def create_session(connection_string, properties, session_id="-1", sql_created=False):
-        cso = get_connection_string_elements(connection_string)
-
-        retry_policy = LinearRetryPolicy(seconds_to_sleep=5, max_retries=5)
-        http_client = LivyReliableHttpClient(cso.url, cso.username, cso.password, retry_policy)
+        http_client = LivyClientFactory.create_http_client(connection_string)
 
         session = LivySession(http_client, session_id, sql_created, properties)
 
         return session
+
+    @staticmethod
+    def create_http_client(connection_string):
+        cso = get_connection_string_elements(connection_string)
+
+        retry_policy = LinearRetryPolicy(seconds_to_sleep=5, max_retries=5)
+        return LivyReliableHttpClient(cso.url, cso.username, cso.password, retry_policy)
diff --git a/remotespark/livyclientlib/reliablehttpclient.py b/remotespark/livyclientlib/reliablehttpclient.py
index bcc14d5..c146dae 100644
--- a/remotespark/livyclientlib/reliablehttpclient.py
+++ b/remotespark/livyclientlib/reliablehttpclient.py
@@ -7,7 +7,6 @@ from time import sleep
 import requests
 
 import remotespark.utils.configuration as conf
-from remotespark.utils.constants import Constants
 from remotespark.utils.log import Log
 from remotespark.utils.utils import get_connection_string
 
diff --git a/remotespark/livyclientlib/sparkcontroller.py b/remotespark/livyclientlib/sparkcontroller.py
index da60fb7..1254f48 100644
--- a/remotespark/livyclientlib/sparkcontroller.py
+++ b/remotespark/livyclientlib/sparkcontroller.py
@@ -20,24 +20,49 @@ class SparkController(object):
         else:
             self.client_manager = ClientManager()
 
-    def run_cell(self, cell, client_name = None):
+    def run_cell(self, cell, client_name=None):
         client_to_use = self.get_client_by_name_or_default(client_name)
         return client_to_use.execute(cell)
 
-    def run_cell_sql(self, cell, client_name = None):
+    def run_cell_sql(self, cell, client_name=None):
         client_to_use = self.get_client_by_name_or_default(client_name)
         return client_to_use.execute_sql(cell)
 
-    def run_cell_hive(self, cell, client_name = None):
+    def run_cell_hive(self, cell, client_name=None):
         client_to_use = self.get_client_by_name_or_default(client_name)
         return client_to_use.execute_hive(cell)
 
+    def get_all_sessions_endpoint(self, connection_string):
+        http_client = self.client_factory.create_http_client(connection_string)
+        r = http_client.get("/sessions", [200])
+        sessions = r.json()["sessions"]
+        session_list = [self.client_factory.create_session(connection_string, {"kind": s["kind"]}, s["id"])
+                        for s in sessions]
+        for s in session_list:
+            s.refresh_status()
+        return session_list
+
+    def get_all_sessions_endpoint_info(self, connection_string):
+        sessions = self.get_all_sessions_endpoint(connection_string)
+        return [str(s) for s in sessions]
+
     def cleanup(self):
         self.client_manager.clean_up_all()
 
+    def cleanup_endpoint(self, connection_string):
+        for session in self.get_all_sessions_endpoint(connection_string):
+            session.delete()
+
     def delete_session_by_name(self, name):
         self.client_manager.delete_client(name)
 
+    def delete_session_by_id(self, connection_string, session_id):
+        http_client = self.client_factory.create_http_client(connection_string)
+        r = http_client.get("/sessions/{}".format(session_id), [200, 404])
+        if r.status_code != 404:
+            session = self.client_factory.create_session(connection_string, {"kind": r.json()["kind"]}, session_id, False)
+            session.delete()
+
     def add_session(self, name, connection_string, skip_if_exists, properties):
         if skip_if_exists and (name in self.client_manager.get_sessions_list()):
             self.logger.debug("Skipping {} because it already exists in list of sessions.".format(name))
@@ -60,4 +85,3 @@ class SparkController(object):
         else:
             client_name = client_name.lower()
             return self.client_manager.get_client(client_name)
-        
diff --git a/remotespark/remotesparkmagics.py b/remotespark/remotesparkmagics.py
index d1f40b3..705954f 100644
--- a/remotespark/remotesparkmagics.py
+++ b/remotespark/remotesparkmagics.py
@@ -43,6 +43,8 @@ class RemoteSparkMagics(Magics):
         except KeyError:
             self.logger.error("Could not read env vars for serialization.")
 
+        self.properties = conf.session_configs()
+
         self.logger.debug("Initialized spark magics.")
 
     @magic_arguments()
@@ -107,12 +109,20 @@ class RemoteSparkMagics(Magics):
 
         # info
         if subcommand == "info":
-            self._print_info()
+            if len(args.command) == 2:
+                connection_string = args.command[1]
+                info_sessions = self.spark_controller.get_all_sessions_endpoint_info(connection_string)
+                self._print_endpoint_info(info_sessions)
+            elif len(args.command) == 1:
+                self._print_local_info()
+            else:
+                raise ValueError("Subcommand 'info' requires no value or a connection string to show all sessions. "
+                                 "{}".format(usage))
         # config
         elif subcommand == "config":
             # Would normally do " ".join(args.command[1:]) but parse_argstring removes quotes...
             rest_of_line = user_input[7:]
-            conf.override(conf.session_configs.__name__, json.loads(rest_of_line))
+            self.properties = json.loads(rest_of_line)
         # add
         elif subcommand == "add":
             if len(args.command) != 4 and len(args.command) != 5:
@@ -127,19 +137,32 @@ class RemoteSparkMagics(Magics):
             else:
                 skip = False
 
-            properties = copy.deepcopy(conf.session_configs())
+            properties = copy.deepcopy(self.properties)
             properties["kind"] = self._get_livy_kind(language)
 
             self.spark_controller.add_session(name, connection_string, skip, properties)
         # delete
         elif subcommand == "delete":
-            if len(args.command) != 2:
-                raise ValueError("Subcommand 'delete' requires an argument. {}".format(usage))
-            name = args.command[1].lower()
-            self.spark_controller.delete_session_by_name(name)
+            if len(args.command) == 2:
+                name = args.command[1].lower()
+                self.spark_controller.delete_session_by_name(name)
+            elif len(args.command) == 3:
+                connection_string = args.command[1]
+                session_id = args.command[2]
+                self.spark_controller.delete_session_by_id(connection_string, session_id)
+            else:
+                raise ValueError("Subcommand 'delete' requires a session name, or a connection string and id. {}"
+                                 .format(usage))
         # cleanup 
         elif subcommand == "cleanup":
-            self.spark_controller.cleanup()
+            if len(args.command) == 2:
+                connection_string = args.command[1]
+                self.spark_controller.cleanup_endpoint(connection_string)
+            elif len(args.command) == 1:
+                self.spark_controller.cleanup()
+            else:
+                raise ValueError("Subcommand 'cleanup' requires no value or a connection string to clean up sessions. "
+                                 "{}".format(usage))
         # run
         elif len(subcommand) == 0:
             if args.context == Constants.context_name_spark:
@@ -170,15 +193,21 @@ class RemoteSparkMagics(Magics):
             self.shell.write_err(e.out)
             return None
 
-    def _print_info(self):
-        sessions_info = ["\t\t{}".format(i) for i in self.spark_controller.get_manager_sessions_str()]
+    def _print_local_info(self):
+        sessions_info = ["        {}".format(i) for i in self.spark_controller.get_manager_sessions_str()]
         print("""Info for running Spark:
     Sessions:
 {}
     Session configs:
         {}
-""".format("\n".join(sessions_info), conf.session_configs()))
+""".format("\n".join(sessions_info), self.properties))
 
+    def _print_endpoint_info(self, info_sessions):
+        sessions_info = ["        {}".format(i) for i in info_sessions]
+        print("""Info for endpoint:
+    Sessions:
+{}
+""".format("\n".join(sessions_info)))
 
     @staticmethod
     def _get_livy_kind(language):
diff --git a/remotespark/utils/configuration.py b/remotespark/utils/configuration.py
index 5668901..df09e52 100644
--- a/remotespark/utils/configuration.py
+++ b/remotespark/utils/configuration.py
@@ -36,23 +36,16 @@ def load(fsrw_class = None):
         overrides = {}
     else:
         overrides = json.loads(line)
-    override_all(overrides)
+    override(overrides)
 
 
-def override_all(obj):
+def override(obj):
     """Given a dictionary representing the overrided defaults for this
     configuration, initialize the global configuration."""
     global _overrides
     _overrides = obj
 
 
-def override(config, value):
-    """Given a string representing a configuration and a value for that configuration,
-    override the configuration. Initialize the overrided configuration beforehand."""
-    initialize()
-    _overrides[config] = value
-
-
 def _override(f):
     """A decorator which first initializes the overrided configurations,
     then checks the global overrided defaults for the given configuration,

Manage livy endpoint from magics
This will be the API:

* `%spark add session_name language conn_string`
  will create a session against the endpoint specified
* `%spark info`
  will display the info for the sessions created in that notebook
* `%spark config <configuration_overrides>`
  will add session configs for subsequent sessions
* `%spark info conn_string`
  will list the sessions for a given livy endpoint by providing `session_id, language, state`
* `%spark delete session_name`
  will delete a session by its name from the notebook that created it
* `%spark delete conn_string session_id`
  will delete a session for a given endpoint by its id
* `%spark cleanup`
  will delete all sessions created by the notebook
* `%spark cleanup conn_string`
  will delete all session for the given livy endpoint

This covers #56, #75, and #76 for magics in Python kernel.
We are not designing the API for the wrapper kernels here and we'll tackle that as a separate improvement.

ping @msftristew @ellisonbg to take a look when they can
diff --git a/tests/test_clientmanager.py b/tests/test_clientmanager.py
index 400fadd..e088b35 100644
--- a/tests/test_clientmanager.py
+++ b/tests/test_clientmanager.py
@@ -30,8 +30,8 @@ def test_deserialize_on_creation():
 
 
 def test_serialize_periodically():
-    conf.override_all({conf.serialize_period_seconds.__name__: 0.1,
-                       conf.serialize_periodically.__name__: True})
+    conf.override({conf.serialize_period_seconds.__name__: 0.1,
+                   conf.serialize_periodically.__name__: True})
     serializer = MagicMock()
     ClientManager(serializer)
 
diff --git a/tests/test_configuration.py b/tests/test_configuration.py
index 8cdac08..92fd020 100644
--- a/tests/test_configuration.py
+++ b/tests/test_configuration.py
@@ -27,7 +27,7 @@ def test_configuration_initialize():
 @with_setup(_setup)
 def test_configuration_initialize_lazy():
     """Tests that the initialize function has no behavior if the override dict is already initialized"""
-    conf.override_all({})
+    conf.override({})
     fsrw_class = MagicMock(side_effect=ValueError)
     conf.initialize(fsrw_class)
 
@@ -56,7 +56,7 @@ def test_configuration_load_not_lazy():
     read_lines = MagicMock(return_value=[json.dumps(config)])
     fsrw.read_lines = read_lines
     fsrw_class = MagicMock(return_value=fsrw)
-    conf.override_all({conf.default_chart_type.__name__: "bar"})
+    conf.override({ conf.default_chart_type.__name__: "bar" })
     conf.load(fsrw_class)
     assert conf._overrides is not None
     assert_equals(conf._overrides, config)
@@ -65,21 +65,9 @@ def test_configuration_load_not_lazy():
 
 @with_setup(_setup)
 def test_configuration_override():
-    kpc = { 'username': 'U', 'password': 'P', 'url': 'L' }
-    overrides = { conf.kernel_python_credentials.__name__: kpc }
-    conf.override_all(overrides)
-    conf.override(conf.execute_timeout_seconds.__name__, 1)
-    assert_equals(conf._overrides, { conf.kernel_python_credentials.__name__: kpc,
-                                     conf.execute_timeout_seconds.__name__: 1 })
-    assert_equals(conf.execute_timeout_seconds(), 1)
-    assert_equals(conf.kernel_python_credentials(), kpc)
-
-
-@with_setup(_setup)
-def test_configuration_override_all():
     z = 1500
     config = { conf.status_sleep_seconds.__name__: z }
-    conf.override_all(config)
+    conf.override(config)
     assert_equals(conf._overrides, config)
     assert_equals(conf.status_sleep_seconds(), z)
 
@@ -88,7 +76,7 @@ def test_configuration_override_all():
 def test_configuration_decorator():
     def test_f():
         return 0
-    conf.override_all({test_f.__name__: -1})
+    conf.override({test_f.__name__: -1})
     test_f_decorated = conf._override(test_f)
     assert_not_equals(test_f_decorated(), test_f())
     assert_equals(test_f_decorated(), -1)
\ No newline at end of file
diff --git a/tests/test_livysession.py b/tests/test_livysession.py
index 1706786..d406532 100644
--- a/tests/test_livysession.py
+++ b/tests/test_livysession.py
@@ -19,6 +19,7 @@ class DummyResponse:
     def json(self):
         return json.loads(self._json_text)
 
+    @property
     def status_code(self):
         return self._status_code
 
@@ -59,7 +60,7 @@ class TestLivySession:
 
     @raises(AssertionError)
     def test_constructor_throws_status_sleep_seconds(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0,
             "statement_sleep_seconds": 2,
             "create_sql_context_timeout_seconds": 60
@@ -69,7 +70,7 @@ class TestLivySession:
 
     @raises(AssertionError)
     def test_constructor_throws_statement_sleep_seconds(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 3,
             "statement_sleep_seconds": 0,
             "create_sql_context_timeout_seconds": 60
@@ -79,7 +80,7 @@ class TestLivySession:
 
     @raises(AssertionError)
     def test_constructor_throws_sql_create_timeout_seconds(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 4,
             "statement_sleep_seconds": 2,
             "create_sql_context_timeout_seconds": 0
@@ -89,7 +90,7 @@ class TestLivySession:
 
     @raises(ValueError)
     def test_constructor_throws_invalid_session_sql_combo(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 2,
             "statement_sleep_seconds": 2,
             "create_sql_context_timeout_seconds": 60
@@ -98,7 +99,7 @@ class TestLivySession:
         conf.load()
 
     def test_constructor_starts_with_existing_session(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 4,
             "statement_sleep_seconds": 2,
             "create_sql_context_timeout_seconds": 60
@@ -111,7 +112,7 @@ class TestLivySession:
         assert session.started_sql_context
 
     def test_constructor_starts_with_no_session(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 4,
             "statement_sleep_seconds": 2,
             "create_sql_context_timeout_seconds": 60
@@ -123,7 +124,7 @@ class TestLivySession:
         assert not session.started_sql_context
 
     def test_is_final_status(self):
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -141,7 +142,7 @@ class TestLivySession:
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
 
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -160,7 +161,7 @@ class TestLivySession:
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
 
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -179,7 +180,7 @@ class TestLivySession:
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
 
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -196,7 +197,7 @@ class TestLivySession:
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
         http_client.get.return_value = DummyResponse(200, self.ready_sessions_json)
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -217,12 +218,12 @@ class TestLivySession:
                               DummyResponse(200, self.ready_sessions_json)]
         http_client.get.side_effect = self._next_response_get
 
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
         session = self._create_session(http_client=http_client)
-        conf.override_all({})
+        conf.override({})
 
         session.start()
 
@@ -240,7 +241,7 @@ class TestLivySession:
                               DummyResponse(200, self.error_sessions_json)]
         http_client.get.side_effect = self._next_response_get
 
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.011,
             "statement_sleep_seconds": 6000
         })
@@ -260,7 +261,7 @@ class TestLivySession:
                               DummyResponse(200, self.ready_sessions_json)]
         http_client.get.side_effect = self._next_response_get
 
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.011,
             "statement_sleep_seconds": 6000
         })
@@ -274,7 +275,7 @@ class TestLivySession:
     def test_delete_session_when_active(self):
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -290,7 +291,7 @@ class TestLivySession:
     def test_delete_session_when_not_started(self):
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -306,7 +307,7 @@ class TestLivySession:
     def test_delete_session_when_dead_throws(self):
         http_client = MagicMock()
         http_client.post.return_value = DummyResponse(201, self.session_create_json)
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -325,7 +326,7 @@ class TestLivySession:
         self.get_responses = [DummyResponse(200, self.running_statement_json),
                               DummyResponse(200, self.ready_statement_json)]
         http_client.get.side_effect = self._next_response_get
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -355,7 +356,7 @@ class TestLivySession:
                               DummyResponse(200, self.ready_sessions_json),
                               DummyResponse(200, self.ready_statement_json)]
         http_client.get.side_effect = self._next_response_get
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -391,7 +392,7 @@ class TestLivySession:
                               DummyResponse(200, self.ready_sessions_json),
                               DummyResponse(200, self.ready_statement_json)]
         http_client.get.side_effect = self._next_response_get
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -420,7 +421,7 @@ class TestLivySession:
                               DummyResponse(200, self.ready_sessions_json),
                               DummyResponse(200, self.ready_statement_json)]
         http_client.get.side_effect = self._next_response_get
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -448,7 +449,7 @@ class TestLivySession:
                               DummyResponse(200, self.running_statement_json),
                               DummyResponse(200, self.ready_statement_json)]
         http_client.get.side_effect = self._next_response_get
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
@@ -466,7 +467,7 @@ class TestLivySession:
         http_client = MagicMock()
         http_client.connection_string = connection_string
         kind = Constants.session_kind_spark
-        conf.override_all({
+        conf.override({
             "status_sleep_seconds": 0.01,
             "statement_sleep_seconds": 0.01
         })
diff --git a/tests/test_remotesparkmagics.py b/tests/test_remotesparkmagics.py
index eaffb2e..e8f2d8f 100644
--- a/tests/test_remotesparkmagics.py
+++ b/tests/test_remotesparkmagics.py
@@ -14,7 +14,7 @@ shell = None
 def _setup():
     global magic, spark_controller, shell
 
-    conf.override_all({})
+    conf.override({})
 
     shell = MagicMock()
     magic = RemoteSparkMagics(shell=None)
@@ -31,7 +31,7 @@ def _teardown():
 @with_setup(_setup, _teardown)
 def test_info_command_parses():
     print_info_mock = MagicMock()
-    magic._print_info = print_info_mock
+    magic._print_local_info = print_info_mock
     command = "info"
 
     magic.spark(command)
@@ -39,6 +39,18 @@ def test_info_command_parses():
     print_info_mock.assert_called_once_with()
 
 
+@with_setup(_setup, _teardown)
+def test_info_endpoint_command_parses():
+    print_info_mock = MagicMock()
+    magic._print_endpoint_info = print_info_mock
+    command = "info conn_str"
+    spark_controller.get_all_sessions_endpoint_info = MagicMock(return_value=None)
+
+    magic.spark(command)
+
+    print_info_mock.assert_called_once_with(None)
+
+
 @with_setup(_setup, _teardown)
 def test_add_sessions_command_parses():
     # Do not skip and python
@@ -70,9 +82,8 @@ def test_add_sessions_command_parses():
 
 @with_setup(_setup, _teardown)
 def test_add_sessions_command_extra_properties():
-    conf.override_all({})
     magic.spark("config {\"extra\": \"yes\"}")
-    assert conf.session_configs() == {"extra": "yes"}
+    assert magic.properties == {"extra": "yes"}
 
     add_sessions_mock = MagicMock()
     spark_controller.add_session = add_sessions_mock
@@ -85,7 +96,6 @@ def test_add_sessions_command_extra_properties():
     magic.spark(line)
 
     add_sessions_mock.assert_called_once_with(name, connection_string, False, {"kind": "spark", "extra": "yes"})
-    conf.load()
 
 
 @with_setup(_setup, _teardown)
@@ -101,6 +111,17 @@ def test_delete_sessions_command_parses():
     mock_method.assert_called_once_with(name)
 
 
+@with_setup(_setup, _teardown)
+def test_delete_sessions_command_parses():
+    mock_method = MagicMock()
+    spark_controller.delete_session_by_id = mock_method
+    line = "delete conn_str 7"
+
+    magic.spark(line)
+
+    mock_method.assert_called_once_with("conn_str", "7")
+
+
 @with_setup(_setup, _teardown)
 def test_cleanup_command_parses():
     mock_method = MagicMock()
@@ -112,6 +133,17 @@ def test_cleanup_command_parses():
     mock_method.assert_called_once_with()
 
 
+@with_setup(_setup, _teardown)
+def test_cleanup_endpoint_command_parses():
+    mock_method = MagicMock()
+    spark_controller.cleanup_endpoint = mock_method
+    line = "cleanup conn_str"
+
+    magic.spark(line)
+
+    mock_method.assert_called_once_with("conn_str")
+
+
 @raises(ValueError)
 @with_setup(_setup, _teardown)
 def test_bad_command_throws_exception():
diff --git a/tests/test_sparkcontroller.py b/tests/test_sparkcontroller.py
index 4b825d0..e522404 100644
--- a/tests/test_sparkcontroller.py
+++ b/tests/test_sparkcontroller.py
@@ -1,5 +1,6 @@
 from mock import MagicMock
 from nose.tools import with_setup
+import json
 
 from remotespark.livyclientlib.sparkcontroller import SparkController
 
@@ -8,6 +9,19 @@ client_factory = None
 controller = None
 
 
+class DummyResponse:
+    def __init__(self, status_code, json_text):
+        self._status_code = status_code
+        self._json_text = json_text
+
+    def json(self):
+        return json.loads(self._json_text)
+
+    @property
+    def status_code(self):
+        return self._status_code
+
+
 def _setup():
     global client_manager, client_factory, controller
 
@@ -78,7 +92,7 @@ def test_cleanup():
 def test_run_cell():
     default_client = MagicMock()
     chosen_client = MagicMock()
-    default_client.execute = chosen_client.execute = MagicMock(return_value=(True,""))
+    default_client.execute = chosen_client.execute = MagicMock(return_value=(True, ""))
     client_manager.get_any_client = MagicMock(return_value=default_client)
     client_manager.get_client = MagicMock(return_value=chosen_client)
     name = "session_name"
@@ -102,7 +116,63 @@ def test_run_cell():
     controller.run_cell_hive(cell, None)
     default_client.execute_hive.assert_called_with(cell)
 
+
 @with_setup(_setup, _teardown)
 def test_get_client_keys():
     controller.get_client_keys()
     client_manager.get_sessions_list.assert_called_once_with()
+
+
+@with_setup(_setup, _teardown)
+def test_get_all_sessions():
+    http_client = MagicMock()
+    http_client.get.return_value = DummyResponse(200, '{"from":0,"total":2,"sessions":[{"id":0,"state":"idle","kind":'
+                                                      '"spark","log":[""]}, {"id":1,"state":"busy","kind":"spark","log"'
+                                                      ':[""]}]}')
+    client_factory.create_http_client.return_value = http_client
+
+    sessions = controller.get_all_sessions_endpoint("conn_str")
+
+    assert len(sessions) == 2
+
+
+@with_setup(_setup, _teardown)
+def test_cleanup_endpoint():
+    s0 = MagicMock()
+    s1 = MagicMock()
+    controller.get_all_sessions_endpoint = MagicMock(return_value=[s0, s1])
+
+    controller.cleanup_endpoint("conn_str")
+
+    s0.delete.assert_called_once_with()
+    s1.delete.assert_called_once_with()
+
+
+@with_setup(_setup, _teardown)
+def test_delete_session_by_id_existent():
+    http_client = MagicMock()
+    http_client.get.return_value = DummyResponse(200, '{"id":0,"state":"starting","kind":"spark","log":[]}')
+    client_factory.create_http_client.return_value = http_client
+    session = MagicMock()
+    create_session_method = MagicMock(return_value=session)
+    client_factory.create_session = create_session_method
+
+    controller.delete_session_by_id("conn_str", "0")
+
+    create_session_method.assert_called_once_with("conn_str", {"kind": "spark"}, "0", False)
+    session.delete.assert_called_once_with()
+
+
+@with_setup(_setup, _teardown)
+def test_delete_session_by_id_non_existent():
+    http_client = MagicMock()
+    http_client.get.return_value = DummyResponse(404, '')
+    client_factory.create_http_client.return_value = http_client
+    session = MagicMock()
+    create_session_method = MagicMock(return_value=session)
+    client_factory.create_session = create_session_method
+
+    controller.delete_session_by_id("conn_str", "0")
+
+    assert len(create_session_method.mock_calls) == 0
+    assert len(session.delete.mock_calls) == 0
diff --git a/tests/test_sparkkernelbase.py b/tests/test_sparkkernelbase.py
index 01bf903..15a9355 100644
--- a/tests/test_sparkkernelbase.py
+++ b/tests/test_sparkkernelbase.py
@@ -54,7 +54,7 @@ def test_get_config():
     url = "url"
 
     config = {"kernel_python_credentials": {user_ev: usr, pass_ev: pwd, url_ev: url}}
-    conf.override_all(config)
+    conf.override(config)
 
     u, p, r = kernel._get_configuration()
 
@@ -67,7 +67,7 @@ def test_get_config():
 
 @with_setup(_setup, _teardown)
 def test_get_config_not_set():
-    conf.override_all({})
+    conf.override({})
     try:
         kernel._get_configuration()
 

pip install -e .
parse_log_pytest
requirements.txt
pytest
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
anyio==4.9.0
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
arrow==1.3.0
async-lru==2.0.5
attrs==25.3.0
babel==2.17.0
beautifulsoup4==4.13.3
bleach==6.2.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
comm==0.2.2
decorator==5.2.1
defusedxml==0.7.1
exceptiongroup==1.2.2
fastjsonschema==2.21.1
fqdn==1.5.1
h11==0.14.0
httpcore==1.0.7
httpx==0.28.1
idna==3.10
importlib_metadata==8.6.1
iniconfig==2.1.0
ipykernel==4.1.1
ipython==4.0.0
ipython-genutils==0.2.0
ipywidgets==7.8.5
isoduration==20.11.0
Jinja2==3.1.6
json5==0.10.0
jsonpointer==3.0.0
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
jupyter-events==0.12.0
jupyter-lsp==2.2.5
jupyter_client==8.6.3
jupyter_core==5.7.2
jupyter_server==2.15.0
jupyter_server_terminals==0.5.3
jupyterlab==4.1.5
jupyterlab_pygments==0.3.0
jupyterlab_server==2.27.3
jupyterlab_widgets==1.1.11
MarkupSafe==3.0.2
mistune==3.1.3
mock==5.2.0
narwhals==1.32.0
nbclient==0.10.2
nbconvert==7.16.6
nbformat==5.10.4
nose==1.3.7
notebook==7.1.3
notebook_shim==0.2.4
numpy==2.0.2
overrides==7.7.0
packaging==24.2
pandas==2.2.3
pandocfilters==1.5.1
pexpect==4.9.0
pickleshare==0.7.5
platformdirs==4.3.7
plotly==6.0.1
pluggy==1.5.0
prometheus_client==0.21.1
ptyprocess==0.7.0
pycparser==2.22
Pygments==2.19.1
pytest==8.3.5
python-dateutil==2.9.0.post0
python-json-logger==3.3.0
pytz==2025.2
PyYAML==6.0.2
pyzmq==26.3.0
referencing==0.36.2
-e git+https://github.com/jupyter-incubator/sparkmagic.git@7025cb5b607abde80d5dd8a701c40c3598801e9d#egg=remotespark
requests==2.32.3
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
rpds-py==0.24.0
Send2Trash==1.8.3
simplegeneric==0.8.1
six==1.17.0
sniffio==1.3.1
soupsieve==2.6
terminado==0.18.1
tinycss2==1.4.0
tomli==2.2.1
tornado==6.4.2
traitlets==5.14.3
types-python-dateutil==2.9.0.20241206
typing_extensions==4.13.0
tzdata==2025.2
uri-template==1.3.0
urllib3==2.3.0
webcolors==24.11.1
webencodings==0.5.1
websocket-client==1.8.0
widgetsnbextension==3.6.10
zipp==3.21.0

name: sparkmagic
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - anyio==4.9.0
      - argon2-cffi==23.1.0
      - argon2-cffi-bindings==21.2.0
      - arrow==1.3.0
      - async-lru==2.0.5
      - attrs==25.3.0
      - babel==2.17.0
      - beautifulsoup4==4.13.3
      - bleach==6.2.0
      - certifi==2025.1.31
      - cffi==1.17.1
      - charset-normalizer==3.4.1
      - comm==0.2.2
      - decorator==5.2.1
      - defusedxml==0.7.1
      - exceptiongroup==1.2.2
      - fastjsonschema==2.21.1
      - fqdn==1.5.1
      - h11==0.14.0
      - httpcore==1.0.7
      - httpx==0.28.1
      - idna==3.10
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - ipykernel==4.1.1
      - ipython==4.0.0
      - ipython-genutils==0.2.0
      - ipywidgets==7.8.5
      - isoduration==20.11.0
      - jinja2==3.1.6
      - json5==0.10.0
      - jsonpointer==3.0.0
      - jsonschema==4.23.0
      - jsonschema-specifications==2024.10.1
      - jupyter-client==8.6.3
      - jupyter-core==5.7.2
      - jupyter-events==0.12.0
      - jupyter-lsp==2.2.5
      - jupyter-server==2.15.0
      - jupyter-server-terminals==0.5.3
      - jupyterlab==4.1.5
      - jupyterlab-pygments==0.3.0
      - jupyterlab-server==2.27.3
      - jupyterlab-widgets==1.1.11
      - markupsafe==3.0.2
      - mistune==3.1.3
      - mock==5.2.0
      - narwhals==1.32.0
      - nbclient==0.10.2
      - nbconvert==7.16.6
      - nbformat==5.10.4
      - nose==1.3.7
      - notebook==7.1.3
      - notebook-shim==0.2.4
      - numpy==2.0.2
      - overrides==7.7.0
      - packaging==24.2
      - pandas==2.2.3
      - pandocfilters==1.5.1
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - platformdirs==4.3.7
      - plotly==6.0.1
      - pluggy==1.5.0
      - prometheus-client==0.21.1
      - ptyprocess==0.7.0
      - pycparser==2.22
      - pygments==2.19.1
      - pytest==8.3.5
      - python-dateutil==2.9.0.post0
      - python-json-logger==3.3.0
      - pytz==2025.2
      - pyyaml==6.0.2
      - pyzmq==26.3.0
      - referencing==0.36.2
      - requests==2.32.3
      - rfc3339-validator==0.1.4
      - rfc3986-validator==0.1.1
      - rpds-py==0.24.0
      - send2trash==1.8.3
      - simplegeneric==0.8.1
      - six==1.17.0
      - sniffio==1.3.1
      - soupsieve==2.6
      - terminado==0.18.1
      - tinycss2==1.4.0
      - tomli==2.2.1
      - tornado==6.4.2
      - traitlets==5.14.3
      - types-python-dateutil==2.9.0.20241206
      - typing-extensions==4.13.0
      - tzdata==2025.2
      - uri-template==1.3.0
      - urllib3==2.3.0
      - webcolors==24.11.1
      - webencodings==0.5.1
      - websocket-client==1.8.0
      - widgetsnbextension==3.6.10
      - zipp==3.21.0
prefix: /opt/conda/envs/sparkmagic

tests/test_clientmanager.py::test_serialize_periodically tests/test_configuration.py::test_configuration_initialize_lazy tests/test_configuration.py::test_configuration_load_not_lazy tests/test_configuration.py::test_configuration_override tests/test_configuration.py::test_configuration_decorator tests/test_sparkkernelbase.py::test_get_config tests/test_sparkkernelbase.py::test_get_config_not_set
tests/test_configuration.py::test_configuration_initialize tests/test_remotesparkmagics.py::test_info_command_parses tests/test_remotesparkmagics.py::test_info_endpoint_command_parses tests/test_remotesparkmagics.py::test_add_sessions_command_parses tests/test_remotesparkmagics.py::test_add_sessions_command_extra_properties tests/test_remotesparkmagics.py::test_delete_sessions_command_parses tests/test_remotesparkmagics.py::test_cleanup_command_parses tests/test_remotesparkmagics.py::test_cleanup_endpoint_command_parses tests/test_remotesparkmagics.py::test_bad_command_throws_exception tests/test_remotesparkmagics.py::test_run_cell_command_parses tests/test_remotesparkmagics.py::test_run_cell_command_writes_to_err tests/test_remotesparkmagics.py::test_run_sql_command_parses tests/test_remotesparkmagics.py::test_run_hive_command_parses tests/test_remotesparkmagics.py::test_run_sql_command_returns_none_when_exception tests/test_remotesparkmagics.py::test_run_hive_command_returns_none_when_exception tests/test_remotesparkmagics.py::test_run_sql_command_stores_variable_in_user_ns tests/test_sparkcontroller.py::test_add_session tests/test_sparkcontroller.py::test_add_session_skip tests/test_sparkcontroller.py::test_delete_session tests/test_sparkcontroller.py::test_cleanup tests/test_sparkcontroller.py::test_run_cell tests/test_sparkcontroller.py::test_get_client_keys tests/test_sparkcontroller.py::test_get_all_sessions tests/test_sparkcontroller.py::test_cleanup_endpoint tests/test_sparkcontroller.py::test_delete_session_by_id_existent tests/test_sparkcontroller.py::test_delete_session_by_id_non_existent tests/test_sparkkernelbase.py::test_do_execute_initializes_magics_if_not_run tests/test_sparkkernelbase.py::test_call_spark tests/test_sparkkernelbase.py::test_execute_throws_if_fatal_error_happened tests/test_sparkkernelbase.py::test_execute_throws_if_fatal_error_happens_for_execution tests/test_sparkkernelbase.py::test_call_spark_sql_new_line tests/test_sparkkernelbase.py::test_call_spark_hive_new_line
tests/test_clientmanager.py::test_get_client_throws_when_client_not_exists tests/test_clientmanager.py::test_deserialize_on_creation tests/test_clientmanager.py::test_get_client tests/test_clientmanager.py::test_delete_client tests/test_clientmanager.py::test_delete_client_throws_when_client_not_exists tests/test_clientmanager.py::test_add_client_throws_when_client_exists tests/test_clientmanager.py::test_client_names_returned tests/test_clientmanager.py::test_get_any_client tests/test_clientmanager.py::test_get_any_client_raises_exception_with_no_client tests/test_clientmanager.py::test_get_any_client_raises_exception_with_two_clients tests/test_clientmanager.py::test_clean_up tests/test_clientmanager.py::test_clean_up_serializer tests/test_configuration.py::test_configuration_load tests/test_sparkkernelbase.py::test_initialize_magics tests/test_sparkkernelbase.py::test_start_session tests/test_sparkkernelbase.py::test_delete_session tests/test_sparkkernelbase.py::test_shutdown_cleans_up
remotespark/remotesparkmagics.py remotespark/utils/configuration.py remotespark/livyclientlib/livyclientfactory.py remotespark/livyclientlib/reliablehttpclient.py remotespark/livyclientlib/sparkcontroller.py
remotespark/remotesparkmagics.py remotespark/utils/configuration.py remotespark/livyclientlib/livyclientfactory.py remotespark/livyclientlib/reliablehttpclient.py remotespark/livyclientlib/sparkcontroller.py