Skip to content

chore: upgrade requirements.txt #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ You can check out this [post](http://ouba.online/blog/2023/3/8/you_probably_dont

`notebook-on-kube` provides the following features:

It provides the following features:
- Authn/authz based on `Kubernetes'`.
- Customize and create notebooks.
- Connect to notebooks.
Expand Down
2 changes: 1 addition & 1 deletion deploy/notebook-on-kube/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v2
name: notebook-on-kube
description: A Helm chart to deploy notebook-on-kube
type: application
version: 0.2.1
version: 0.2.2
home: https://github.com/machine424/notebook-on-kube
dependencies:
- name: ingress-nginx
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "notebook-on-kube"
version = "0.2.1"
version = "0.2.2"
description = "A tool to deploy Notebooks on Kubernetes."
readme = "README.md"
authors = [
Expand All @@ -25,7 +25,7 @@ dependencies = [
notebook-on-kube = "notebook_on_kube.main:run"

[project.optional-dependencies]
test = ["black", "isort", "flake8", "mypy", "pytest", "pytest-mock", "requests"]
test = ["black", "isort", "flake8", "mypy", "pytest", "pytest-mock", "httpx"]

[project.urls]
"Homepage" = "https://github.com/machine424/notebook-on-kube"
Expand Down
16 changes: 7 additions & 9 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,31 @@ anyio==3.6.2
# via starlette
click==8.1.3
# via uvicorn
fastapi==0.85.1
fastapi==0.93.0
# via notebook-on-kube (pyproject.toml)
h11==0.14.0
# via uvicorn
idna==3.4
# via anyio
jinja2==3.1.2
# via notebook-on-kube (pyproject.toml)
markupsafe==2.1.1
markupsafe==2.1.2
# via jinja2
pydantic==1.10.2
pydantic==1.10.5
# via fastapi
pyjwt==2.6.0
# via notebook-on-kube (pyproject.toml)
python-multipart==0.0.5
python-multipart==0.0.6
# via notebook-on-kube (pyproject.toml)
ruamel-yaml==0.17.21
# via notebook-on-kube (pyproject.toml)
ruamel-yaml-clib==0.2.7
# via ruamel-yaml
six==1.16.0
# via python-multipart
sniffio==1.3.0
# via anyio
starlette==0.20.4
starlette==0.25.0
# via fastapi
typing-extensions==4.4.0
typing-extensions==4.5.0
# via pydantic
uvicorn==0.19.0
uvicorn==0.20.0
# via notebook-on-kube (pyproject.toml)
1 change: 0 additions & 1 deletion src/notebook_on_kube/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,6 @@ def form_data_to_values_file(cls, *, form_data: FormData) -> IO | None:

class NotebookStatus:
class Notebook(BaseModel, extra=Extra.forbid):

missing_statefulset: ClassVar[str] = "StatefulSet Missing"
not_running: ClassVar[str] = "Not Running"
error: ClassVar[str] = "Error"
Expand Down
57 changes: 31 additions & 26 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
)
FAKE_NOTEBOOK = "my-notebook"

client = TestClient(app)

@pytest.fixture()
def test_client():
return TestClient(app)


@pytest.fixture()
Expand Down Expand Up @@ -131,30 +134,32 @@ def test_complete_notebook_name_from_form(mocker, notebook_name, username, compl
assert complete_notebook_name_from_form(notebook_name=notebook_name, username=username) == complete_notebook_name


def test_healthz():
response = client.get("api/healthz")
def test_healthz(test_client):
response = test_client.get("api/healthz")
assert response.status_code == 200
assert response.json()["status"] == "Seems healthy"


def test_root():
response = client.get("/")
def test_root(test_client):
response = test_client.get("/")
assert response.status_code == 200
assert response.template.name == "index.html"
assert response.context["kube_cluster_name"] is None


def test_login(validate_kube_token_mock):
response = client.post("api/login/", data={"kube_token": FAKE_OIDC_TOKEN}, allow_redirects=False)
def test_login(validate_kube_token_mock, test_client):
response = test_client.post("api/login/", data={"kube_token": FAKE_OIDC_TOKEN}, follow_redirects=False)
assert response.status_code == 303
assert response.headers["location"] == "/api/notebooks/"
# We do not send the cookie when connecting to Notebooks (non /api)
assert response.cookies.get_dict(path="/api")["kube_token"] == FAKE_OIDC_TOKEN
# Assert we only set the cookie on /api)
assert len(response.cookies) == 1
assert response.cookies.get(name="kube_token", path="/api") == FAKE_OIDC_TOKEN


def test_notebooks(mocker, validate_kube_token_mock):
helm = mocker.patch("notebook_on_kube.main.helm", return_value="{}")
response = client.get("api/notebooks/", cookies={"kube_token": FAKE_OIDC_TOKEN})
client = TestClient(app=app, cookies={"kube_token": FAKE_OIDC_TOKEN})
response = client.get("api/notebooks/")
helm.assert_called_once_with(
body=["list", "--filter", f"^nok-{FAKE_USERNAME}-.+$", "--all", "--output", "json"], kube_token=FAKE_OIDC_TOKEN
)
Expand All @@ -177,9 +182,8 @@ def test_delete_notebook(mocker, validate_kube_token_mock, existing, helm_list_o
helm_list_call = mocker.call(
body=["list", "--filter", f"^{FAKE_NOTEBOOK}$", "--all", "--output", "json"], kube_token=FAKE_OIDC_TOKEN
)
response = client.post(
f"api/delete_notebook/{FAKE_NOTEBOOK}", cookies={"kube_token": FAKE_OIDC_TOKEN}, allow_redirects=False
)
client = TestClient(app=app, cookies={"kube_token": FAKE_OIDC_TOKEN})
response = client.post(f"api/delete_notebook/{FAKE_NOTEBOOK}", follow_redirects=False)
assert response.status_code == status_code
if existing:
assert response.headers["location"] == "/api/notebooks/"
Expand All @@ -195,7 +199,8 @@ def test_delete_notebook(mocker, validate_kube_token_mock, existing, helm_list_o
def test_notebook_events(mocker, validate_kube_token_mock, event):
mocker.patch("notebook_on_kube.main.notebook_exists", return_value=True)
kubectl = mocker.patch("notebook_on_kube.main.kubectl", return_value=event)
response = client.get(f"api/notebook_events/{FAKE_NOTEBOOK}", cookies={"kube_token": FAKE_OIDC_TOKEN})
client = TestClient(app=app, cookies={"kube_token": FAKE_OIDC_TOKEN})
response = client.get(f"api/notebook_events/{FAKE_NOTEBOOK}")
assert response.status_code == 200
assert (
response.text
Expand Down Expand Up @@ -224,10 +229,10 @@ def test_notebook_events(mocker, validate_kube_token_mock, event):
def test_scale_notebook(mocker, validate_kube_token_mock, scale):
mocker.patch("notebook_on_kube.main.notebook_exists", return_value=True)
kubectl = mocker.patch("notebook_on_kube.main.kubectl")
client = TestClient(app=app, cookies={"kube_token": FAKE_OIDC_TOKEN})
response = client.get(
f"api/scale_notebook/{FAKE_NOTEBOOK}?scale={scale}",
cookies={"kube_token": FAKE_OIDC_TOKEN},
allow_redirects=False,
follow_redirects=False,
)
assert response.status_code == 303
assert response.headers["location"] == "/api/notebooks/"
Expand All @@ -245,9 +250,9 @@ def test_scale_notebook(mocker, validate_kube_token_mock, scale):


def test_new_notebook(validate_kube_token_mock):
client = TestClient(app=app, cookies={"kube_token": FAKE_OIDC_TOKEN})
response = client.get(
"api/new_notebook/",
cookies={"kube_token": FAKE_OIDC_TOKEN},
)
assert response.status_code == 200
assert response.template.name == "new_notebook.html"
Expand All @@ -270,14 +275,20 @@ def test_create_notebook(mocker, validate_kube_token_mock, existing, helm_values
yaml_load = mocker.spy(yaml, "load")
yaml_dump = mocker.spy(yaml, "dump")

client = TestClient(app=app, cookies={"kube_token": FAKE_OIDC_TOKEN})
response = client.post(
"api/create_notebook/",
cookies={"kube_token": FAKE_OIDC_TOKEN},
data={"notebook_name": FAKE_NOTEBOOK, "helm_values": helm_values},
allow_redirects=False,
follow_redirects=False,
)
assert response.status_code == status_code
if not existing:
if existing:
assert (
response.json()["detail"]
== f"The Notebook notebook_name='nok-{FAKE_USERNAME}-{FAKE_NOTEBOOK}' already exists."
)
assert helm.call_count == 0
else:
assert response.headers["location"] == "/api/notebooks/"
# helm_values content was retrieved
yaml_load.assert_called_once_with(helm_values)
Expand All @@ -296,9 +307,3 @@ def test_create_notebook(mocker, validate_kube_token_mock, existing, helm_values
],
kube_token=FAKE_OIDC_TOKEN,
)
else:
assert (
response.json()["detail"]
== f"The Notebook notebook_name='nok-{FAKE_USERNAME}-{FAKE_NOTEBOOK}' already exists."
)
assert helm.call_count == 0