You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by ku...@apache.org on 2021/12/07 05:46:47 UTC

[submarine] branch master updated: Submarine 1095. Incorporate Click CLI in SDK

This is an automated email from the ASF dual-hosted git repository.

kuanhsun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 5eb043f  Submarine 1095. Incorporate Click CLI in SDK
5eb043f is described below

commit 5eb043fa9d230cae363ade6fc2859b5e9507afee
Author: atosystem <at...@hotmail.com>
AuthorDate: Tue Dec 7 12:38:05 2021 +0800

    Submarine 1095. Incorporate Click CLI in SDK
    
    ### What is this PR for?
    Introduce click module to submarine SDK.
    
    Allowing the followings commands
    ```
    submarine sandbox start # create submarine sandbox
    submarine sandbox start --version 0.6.0
    submarine sandbox delete # delete submarine sandbox
    
    submarine get experiment <id>
    submarine get notebook <id>
    submarine get environment <id>
    
    submarine list experiment
    submarine list notebook
    submarine list environment
    
    submarine delete experiment <id>
    submarine delete notebook <id>
    submarine delete environment <id>
    ```
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    * [ ] - Connect backend API
    * [ ] - Write docs for CLI
    
    ### What is the Jira issue?
    [SUBMARINE-1095](https://issues.apache.org/jira/browse/SUBMARINE-1095)
    
    ### How should this be tested?
    
    python unit tests are implemented for command line testing
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Do the license files need updating? No
    * Are there breaking changes for older versions? No
    * Does this need new documentation? Yes
    
    Author: atosystem <at...@hotmail.com>
    
    Signed-off-by: kuanhsun <ku...@apache.org>
    
    Closes #817 from atosystem/SUBMARINE-1095 and squashes the following commits:
    
    8418f3a2 [atosystem] SUBMARINE-1095. Remove comments
    18eb2a12 [atosystem] SUBMARINE-1095. Add: basic cli stucture test
    a27af6ab [atosystem] SUBMARINE-1095. autoformat2
    b1a48755 [atosystem] SUBMARINE-1095. autoformat
    598b3749 [atosystem] SUBMARINE-1095. Add: basic cli structure
---
 submarine-sdk/pysubmarine/setup.py                 |  6 ++
 .../pysubmarine/submarine/cli/__init__.py          | 31 ++++++++++
 .../submarine/cli/environment/__init__.py          | 22 +++++++
 .../submarine/cli/environment/command.py           | 38 ++++++++++++
 .../submarine/cli/experiment/__init__.py           | 22 +++++++
 .../submarine/cli/experiment/command.py            | 38 ++++++++++++
 submarine-sdk/pysubmarine/submarine/cli/main.py    | 67 ++++++++++++++++++++++
 .../pysubmarine/submarine/cli/notebook/__init__.py | 22 +++++++
 .../pysubmarine/submarine/cli/notebook/command.py  | 38 ++++++++++++
 .../pysubmarine/submarine/cli/sandbox/__init__.py  | 21 +++++++
 .../pysubmarine/submarine/cli/sandbox/command.py   | 31 ++++++++++
 .../pysubmarine/tests/cli/test_environment.py      | 41 +++++++++++++
 .../pysubmarine/tests/cli/test_experiment.py       | 41 +++++++++++++
 .../pysubmarine/tests/cli/test_notebook.py         | 41 +++++++++++++
 .../pysubmarine/tests/cli/test_sandbox.py          | 39 +++++++++++++
 15 files changed, 498 insertions(+)

diff --git a/submarine-sdk/pysubmarine/setup.py b/submarine-sdk/pysubmarine/setup.py
index e1291ac..1e72068 100644
--- a/submarine-sdk/pysubmarine/setup.py
+++ b/submarine-sdk/pysubmarine/setup.py
@@ -40,6 +40,7 @@ setup(
         "pyarrow==0.17.0",
         "mlflow>=1.15.0",
         "boto3>=1.17.58",
+        "click==8.0.3",
     ],
     extras_require={
         "tf": ["tensorflow==1.15.0"],
@@ -58,6 +59,11 @@ setup(
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
     ],
+    entry_points={
+        "console_scripts": [
+            "submarine = submarine.cli.main:entry_point",
+        ],
+    },
     license="Apache License, Version 2.0",
     maintainer="Apache Submarine Community",
     maintainer_email="dev@submarine.apache.org",
diff --git a/submarine-sdk/pysubmarine/submarine/cli/__init__.py b/submarine-sdk/pysubmarine/submarine/cli/__init__.py
new file mode 100644
index 0000000..a4665f6
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/__init__.py
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# coding: utf-8
+
+# flake8: noqa
+"""
+    Submarine Command Line Interface
+
+    The Submarine CLI allows you to interact with submarine backend via command line.
+
+    The version of the OpenAPI document: 0.7.0-SNAPSHOT
+    Contact: dev@submarine.apache.org
+    Generated by: https://openapi-generator.tech
+"""
+
+from __future__ import absolute_import
+
+__version__ = "0.7.0-SNAPSHOT"
diff --git a/submarine-sdk/pysubmarine/submarine/cli/environment/__init__.py b/submarine-sdk/pysubmarine/submarine/cli/environment/__init__.py
new file mode 100644
index 0000000..38a7a27
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/environment/__init__.py
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from submarine.cli.environment.command import delete_environment, get_environment, list_environment
+
+__all__ = [
+    "get_environment",
+    "list_environment",
+    "delete_environment",
+]
diff --git a/submarine-sdk/pysubmarine/submarine/cli/environment/command.py b/submarine-sdk/pysubmarine/submarine/cli/environment/command.py
new file mode 100644
index 0000000..85c620f
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/environment/command.py
@@ -0,0 +1,38 @@
+"""
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+"""
+
+import click
+
+
+@click.command("environment")
+def list_environment():
+    """List environment"""
+    click.echo("list environment!")
+
+
+@click.command("environment")
+@click.argument("id")
+def get_environment(id):
+    """Get environment"""
+    click.echo("get environment! id={}".format(id))
+
+
+@click.command("environment")
+@click.argument("id")
+def delete_environment(id):
+    """Delete environment"""
+    click.echo("delete environment! id={}".format(id))
diff --git a/submarine-sdk/pysubmarine/submarine/cli/experiment/__init__.py b/submarine-sdk/pysubmarine/submarine/cli/experiment/__init__.py
new file mode 100644
index 0000000..1e6253c
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/experiment/__init__.py
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from submarine.cli.experiment.command import delete_experiment, get_experiment, list_experiment
+
+__all__ = [
+    "get_experiment",
+    "list_experiment",
+    "delete_experiment",
+]
diff --git a/submarine-sdk/pysubmarine/submarine/cli/experiment/command.py b/submarine-sdk/pysubmarine/submarine/cli/experiment/command.py
new file mode 100644
index 0000000..6f2c182
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/experiment/command.py
@@ -0,0 +1,38 @@
+"""
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+"""
+
+import click
+
+
+@click.command("experiment")
+def list_experiment():
+    """List experiments"""
+    click.echo("list experiment!")
+
+
+@click.command("experiment")
+@click.argument("id")
+def get_experiment(id):
+    """Get experiments"""
+    click.echo("get experiment! id={}".format(id))
+
+
+@click.command("experiment")
+@click.argument("id")
+def delete_experiment(id):
+    """Delete experiment"""
+    click.echo("delete experiment! id={}".format(id))
diff --git a/submarine-sdk/pysubmarine/submarine/cli/main.py b/submarine-sdk/pysubmarine/submarine/cli/main.py
new file mode 100644
index 0000000..b8a699b
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/main.py
@@ -0,0 +1,67 @@
+"""
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+"""
+
+import click
+
+from submarine.cli.environment import command as environment_cmd
+from submarine.cli.experiment import command as experiment_cmd
+from submarine.cli.notebook import command as notebook_cmd
+from submarine.cli.sandbox import command as sandbox_cmd
+
+
+@click.group()
+def entry_point():
+    """Submarine CLI Tool!"""
+    pass
+
+
+@entry_point.group("list")
+def cmdgrp_list():
+    pass
+
+
+@entry_point.group("get")
+def cmdgrp_get():
+    pass
+
+
+@entry_point.group("delete")
+def cmdgrp_delete():
+    pass
+
+
+@entry_point.group("sandbox")
+def cmdgrp_sandbox():
+    pass
+
+
+# experiment
+cmdgrp_list.add_command(experiment_cmd.list_experiment)
+cmdgrp_get.add_command(experiment_cmd.get_experiment)
+cmdgrp_delete.add_command(experiment_cmd.delete_experiment)
+# notebook
+cmdgrp_list.add_command(notebook_cmd.list_notebook)
+cmdgrp_get.add_command(notebook_cmd.get_notebook)
+cmdgrp_delete.add_command(notebook_cmd.delete_notebook)
+# environment
+cmdgrp_list.add_command(environment_cmd.list_environment)
+cmdgrp_get.add_command(environment_cmd.get_environment)
+cmdgrp_delete.add_command(environment_cmd.delete_environment)
+
+# sandbox
+cmdgrp_sandbox.add_command(sandbox_cmd.start_sandbox)
+cmdgrp_sandbox.add_command(sandbox_cmd.delete_sandbox)
diff --git a/submarine-sdk/pysubmarine/submarine/cli/notebook/__init__.py b/submarine-sdk/pysubmarine/submarine/cli/notebook/__init__.py
new file mode 100644
index 0000000..0dfd20f
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/notebook/__init__.py
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from submarine.cli.notebook.command import delete_notebook, get_notebook, list_notebook
+
+__all__ = [
+    "get_notebook",
+    "list_notebook",
+    "delete_notebook",
+]
diff --git a/submarine-sdk/pysubmarine/submarine/cli/notebook/command.py b/submarine-sdk/pysubmarine/submarine/cli/notebook/command.py
new file mode 100644
index 0000000..8deb3cb
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/notebook/command.py
@@ -0,0 +1,38 @@
+"""
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+"""
+
+import click
+
+
+@click.command("notebook")
+def list_notebook():
+    """List notebooks"""
+    click.echo("list notebook!")
+
+
+@click.command("notebook")
+@click.argument("id")
+def get_notebook(id):
+    """Get notebooks"""
+    click.echo("get notebook! id={}".format(id))
+
+
+@click.command("notebook")
+@click.argument("id")
+def delete_notebook(id):
+    """Delete notebook"""
+    click.echo("delete notebook! id={}".format(id))
diff --git a/submarine-sdk/pysubmarine/submarine/cli/sandbox/__init__.py b/submarine-sdk/pysubmarine/submarine/cli/sandbox/__init__.py
new file mode 100644
index 0000000..ee8f305
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/sandbox/__init__.py
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from submarine.cli.sandbox.command import delete_sandbox, start_sandbox
+
+__all__ = [
+    "start_sandbox",
+    "delete_sandbox",
+]
diff --git a/submarine-sdk/pysubmarine/submarine/cli/sandbox/command.py b/submarine-sdk/pysubmarine/submarine/cli/sandbox/command.py
new file mode 100644
index 0000000..fecaf1a
--- /dev/null
+++ b/submarine-sdk/pysubmarine/submarine/cli/sandbox/command.py
@@ -0,0 +1,31 @@
+"""
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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.
+"""
+
+import click
+
+
+@click.command("start")
+@click.option("-v", "--version", "version", help="Specify sandbox version", default="0.6.0")
+def start_sandbox(version):
+    """Start sandbox"""
+    click.echo("start sandbox! version={}".format(version))
+
+
+@click.command("delete")
+def delete_sandbox():
+    """Delete sandbox"""
+    click.echo("delete sandbox!")
diff --git a/submarine-sdk/pysubmarine/tests/cli/test_environment.py b/submarine-sdk/pysubmarine/tests/cli/test_environment.py
new file mode 100644
index 0000000..7240bf1
--- /dev/null
+++ b/submarine-sdk/pysubmarine/tests/cli/test_environment.py
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from click.testing import CliRunner
+
+from submarine.cli import main
+
+
+def test_list_environment():
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["list", "environment"])
+    assert result.exit_code == 0
+    assert "list environment!" in result.output
+
+
+def test_get_environment():
+    mock_environment_id = "0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["get", "environment", mock_environment_id])
+    assert result.exit_code == 0
+    assert "get environment! id={}".format(mock_environment_id) in result.output
+
+
+def test_delete_environment():
+    mock_environment_id = "0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["delete", "environment", mock_environment_id])
+    assert result.exit_code == 0
+    assert "delete environment! id={}".format(mock_environment_id) in result.output
diff --git a/submarine-sdk/pysubmarine/tests/cli/test_experiment.py b/submarine-sdk/pysubmarine/tests/cli/test_experiment.py
new file mode 100644
index 0000000..8d2ff44
--- /dev/null
+++ b/submarine-sdk/pysubmarine/tests/cli/test_experiment.py
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from click.testing import CliRunner
+
+from submarine.cli import main
+
+
+def test_list_experiment():
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["list", "experiment"])
+    assert result.exit_code == 0
+    assert "list experiment!" in result.output
+
+
+def test_get_experiment():
+    mock_experiment_id = "0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["get", "experiment", mock_experiment_id])
+    assert result.exit_code == 0
+    assert "get experiment! id={}".format(mock_experiment_id) in result.output
+
+
+def test_delete_experiment():
+    mock_experiment_id = "0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["delete", "experiment", mock_experiment_id])
+    assert result.exit_code == 0
+    assert "delete experiment! id={}".format(mock_experiment_id) in result.output
diff --git a/submarine-sdk/pysubmarine/tests/cli/test_notebook.py b/submarine-sdk/pysubmarine/tests/cli/test_notebook.py
new file mode 100644
index 0000000..83bb47a
--- /dev/null
+++ b/submarine-sdk/pysubmarine/tests/cli/test_notebook.py
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from click.testing import CliRunner
+
+from submarine.cli import main
+
+
+def test_list_notebook():
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["list", "notebook"])
+    assert result.exit_code == 0
+    assert "list notebook!" in result.output
+
+
+def test_get_notebook():
+    mock_notebook_id = "0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["get", "notebook", mock_notebook_id])
+    assert result.exit_code == 0
+    assert "get notebook! id={}".format(mock_notebook_id) in result.output
+
+
+def test_delete_notebook():
+    mock_notebook_id = "0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["delete", "notebook", mock_notebook_id])
+    assert result.exit_code == 0
+    assert "delete notebook! id={}".format(mock_notebook_id) in result.output
diff --git a/submarine-sdk/pysubmarine/tests/cli/test_sandbox.py b/submarine-sdk/pysubmarine/tests/cli/test_sandbox.py
new file mode 100644
index 0000000..fb8d9ee
--- /dev/null
+++ b/submarine-sdk/pysubmarine/tests/cli/test_sandbox.py
@@ -0,0 +1,39 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+from click.testing import CliRunner
+
+from submarine.cli import main
+
+
+def test_start_sandbox():
+    default_version = "0.6.0"
+    mock_version = "0.0.0"
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["sandbox", "start"])
+    assert result.exit_code == 0
+    assert "start sandbox! version={}".format(default_version) in result.output
+
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["sandbox", "start", "-v", mock_version])
+    assert result.exit_code == 0
+    assert "start sandbox! version={}".format(mock_version) in result.output
+
+
+def test_delete_sandbox():
+    runner = CliRunner()
+    result = runner.invoke(main.entry_point, ["sandbox", "delete"])
+    assert result.exit_code == 0
+    assert "delete sandbox!" in result.output

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org